Fluent NHibernate - Multiple collections in the same table - c#-4.0

Im working on rebuilding a clients software and they want to keep their database as unmodified as possible.
I got a table where they collect users and orders for different companies, no biggie there but the twist is they do it for multiple entities.
for example the table looks like this:
ID
UserID
Index
CompanyID
Type
lets say they got entities like Project and Workflow, then the Type column would be 'P' for projects and 'W' for workflows. So on a ID is the ID of a Project or Workflow Identity. UserID is always a foreign key to a User entity and Index is the order that the user is used when this Project/Workflow is used. And CompanyID is what company owns project or workflow entity.
I have tried to search google for this but i came up with nothing.
What i want is on a Template entity map two collections say StandardProjectUsers and StandardWorkflowUsers and they should collect them from correct entities with a user and index for current company.
Is this at all possible with fluent nhibernate ?

A nice article on how to do it: http://www.philliphaydon.com/2011/08/fluent-nhibernate-table-inheritance-discriminators/
You are looking at a table-per-hierarchy strategy.
In a nutshell you use:
public class BaseClassMap : ClassMap<BaseClass>
{
public BaseClassMap()
{
DiscriminateSubClassesOnColumn("Type");
...
}
}
public class WorkflowMap : SubclassMap<Workflow>
{
public WorkflowMap()
{
DiscriminatorValue("W");
...
}
}
public class ProjectMap : SubclassMap<Project>
{
public ProjectMap()
{
DiscriminatorValue("P");
...
}
}

Related

How to extend the core customer table?

I created a custom table with additional settings for customers. Next I added a field to the customer core table in which I'd like to store the id choice per customer. I extended with EntityExtensionInterface the customerDefinition :
public function extendFields(FieldCollection $collection): void
{
$collection->add(
(new OneToOneAssociationField(
'customerSetting',
'customer_setting',
'id',
WdtCustomerSettingsDefinition::class,
true
))->addFlags(new Inherited())
);
}
public function getDefinitionClass(): string
{
return CustomerDefinition::class;
}
When I manually manipulate the customer table, with an id from my custom table in the added field, I can retrieve and use the settings from my custom table in the storefront.
For the backend I created a single select to the entity custom_table,
<sw-entity-single-select entity="wdt_customer_settings" v-model="customer.extensions.customerSetting.id" >
</sw-entity-single-select>
and with the manually 'injected' id from the custom table, this choice indicates indeed 'selected' However, after changing to another choice and saving results in an error: Customer could not be saved.
What am I missing?
You should look always to the ajax responses. There is the explict error which is occured. Do you added some boilerplate code to check that your extensions is always available? Otherwise it would cause issues on new entities

how can i fill controller with data - SQL Function in Entity Framework?

i have create an sql function in my database that take to Date params and get data from 5 tables.
after that add it to project as entity framework from database and the code generated is:
[DbFunction("Dr_EmploEntities", "SelectEmployee")]
public virtual IQueryable SelectEmployee(Nullable frm_date, Nullable to_date)
{
var frm_dateParameter = frm_date.HasValue ?
new ObjectParameter("frm_date", frm_date) :
new ObjectParameter("frm_date", typeof(DateTime));
var to_dateParameter = to_date.HasValue ?
new ObjectParameter("to_date", to_date) :
new ObjectParameter("to_date", typeof(DateTime));
return ((IObjectContextAdapter)this).ObjectContext.CreateQuery("[Dr_EmploEntities].[SelectEmployee](#frm_date, #to_date)", frm_dateParameter, to_dateParameter);
}
public DbSet SelectEmployee_Result { get; set; }
as you see i have now "SelectEmployee_Result" that don't take any params, and "SelectEmployee" that take two date params.
after that i have create an controller for "SelectEmployee_Result" class.
after that i run my project Index View that working with "SelectEmployee_Result" class give me err:
"The type 'SelectEmployee_Result' is mapped as a complex type. The Set method, DbSet objects, and DbEntityEntry objects can only be used with entity types, not complex types."
and i make breakpoint and see that "SelectEmployee_Result" has no data so i change the Index Code in controller and fill "SelectEmployee" with two date params
and when run got same err msg too.
so how can i fill "SelectEmployee_Result" from the beginning with data between two dates to let me use it in all views ?
all what i need here is view data i got i edit before saving it in database Like using DataTable but i need to do that from Entity with sql function
and what is difference between "SelectEmployee" that is my function name and that is need two params and "SelectEmployee_Result"?

How to specify a column Name for EF5 navigation property

I'm using EF5 code first to generate my database schema, but my new navigation property is being named in an undesirable way in the table. here is the model I'm working with.
public class User
{
[Key]
public long UserId { get; set; }
...
**public virtual ICollection<ImagePermission> KeepThisNavigationName { get; set; }**
}
However, After I've updated my database and examine the table columns, the column is named:
dbo.ImagePermission.User_UserId
And I would like it to be named
dbo.ImagePermission.KeepThisNavigationName_UserId
I believe there is a way to do this using the Fluent API, but after many failed attempts, I can't get the desired outcome.
P.s. The 'ImagePermission' Entity is currently still in development, so I would prefer to drop the migration which creates this table so I can create this column name correctly during the table create, rather than having additional code to update the column name.
Many thanks, Oliver
The correct mapping with Fluent API would be:
modelBuilder.Entity<User>()
.HasMany(u => u.KeepThisNavigationName)
.WithOptional() // or WithRequired()
.Map(m => m.MapKey("KeepThisNavigationName_UserId"));
If you have a navigation property in ImagePermission refering to User you need to use WithOptional(i => i.User) (or WithRequired(i => i.User)) instead of the parameterless version.

Get old data in preUpdate Sonata Admin Bundle

I have a product entity and it has an images field that store the images names from the product but the images names depends of a part_number field that is unique, so if the user make a mistake in the part number and he wants to edit it then I also have to change the images names
I tried this but it does not works:
// class ProductsAdmin extends Admin
public function preUpdate($product) {
$old_product = $this->getSubject();
if ($old_product->getPartNumber() != $product->getPartNumber)
{
// change file names
}
$this->saveFile($product);
}
How I get the original row in preUpdate() function?
According to the topic taken from the official SonataAdmin google forum:
https://groups.google.com/forum/#!topic/sonata-devs/0zML6N13i3U
you need to make use of the class UnitOfWork:
http://www.doctrine-project.org/api/orm/2.3/class-Doctrine.ORM.UnitOfWork.html
Do this way:
public function preUpdate($object)
{
$em = $this->getModelManager()->getEntityManager($this->getClass());
$original = $em->getUnitOfWork()->getOriginalDocumentData($object);
}
Thus you get an array of values of your database entity.
E.g: to get access to the value password of your entity do:
$password = $original['password'];
That's all.
Enjoy :)
If you just do a doctrine query in the preUpdate function to get the product from the database you'll have the old object. Then do the comparison and you're good to go.

DDD - Repository Pattern returning db keys?

There is a big design flaw here, but I'm having trouble solving it:
The business need is a little involved so I'll try to keep this simple.
We have a table with purchases, and a table for returns. When a return is made, we have to find match that return to the oldest purchase in the db, and record that in a "returns applied" table.
So, when I insert a Return, within that transaction, I need to apply the return to a purchase record.
As it stands now, we have a service that calls the repository for the insert. The service needs to know what the key is of that inserted record, so that it can finish the transaction by inserting an "applied" record using that key.
We're basically stuck because my understanding is that a repository should not return this kind of data. Doesn't this defeat the idea of the Repository being a collection?
What is the alternative?
CLARIFICATION:
We have a Purchase table, a Return table, and an Applied table
The applied table looks like this
purchaseId returnId qtyReturned
So when a return is inserted I need the id of a purchase (decided by some business rules) and the id of the newly inserted return.
I suppose the following according to your question:
public class Purchase {
// ReturnRepository plays the role of collaborator
public Return returnMe(PurchaseRepository purchaseRepository, int quantity) {
return purchaseRepository.returnPurchase(this, quantity);
}
}
public class PurchaseRepositoryImpl implements PurchaseRepository {
// returnd Purchase object has its id set up
public Purchase getOldestPurchase() {
// logic in order to get oldest purchase
}
public Return returnPurchase(Purchase purchase, quantity) {
// logic in order to save a return record
// Some ORM frameworks returns ids when a record is saved. In my case, Hibernate or NHibernate (.NET) fulfill ths requirement
// Then purchaseId, returnId and quantity is saved in "returns applied" table
}
}
public class PurchaseServiceImpl implements PurchaseService {
// Injected through dependency injection
private PurchaseRepository purchaseRepository;
// Spring transaction boundary, for example
// Notice returnPurchase method returns a Return object
public Return returnPurchase(int quantity) {
Purchase purchase = purchaseRepository.getOldestPurchase();
return purchase.returnMe(purchaseRepository, quantity);
}
}

Resources