I'm a bit confused how to work properly with many-to-many relationships in locally created objects.
I've prepared a small example to demonstrate the issue.
There are two tables and one mapping table:
And data in tables:
Entity Framework has created two tables and many-to-many relation:
Now run the application and load single student (with ID=1 and his classrooms).
If student was loaded from the database then everything is fine and EF gets 2 classrooms:
But in case user was created locally (with the same Id but changed Name) and attached to the EF then classrooms are not loaded (studentLocal variable).
The same situation if I try to load student from EF - it gets the local user (student variable has Name="xx") and no classrooms:
On the view user can change classrooms for student as well as change student properties so I need to update Student table and merge StudentClassroom table.
What is the best way to deal in this case? I don't want to load each
postback student entity again and again.
Is there a way to load
Classrooms for locally created Student which exist in the database?
How to merge StudentClassroom records? I know only one - load
existed records and new one and merge then either deleting all of
them and recreating from the new list either manually determining
which records should be deleted/updated/created. Is there a better
approach?
Your problem is that EF is not creating the right tables for your model. It should be creating 3 classes not 2. Probably the reason it isn't is that you don't have the relations set up properly in the database. If you are using SQL Server try using the diagram feature to check your relationships and Primary Keys are correctly set up before you set up the model.
Related
Im currently working in a team that uses EF as the ORM of choice.
We have a common project that contains many EDMX files.
The reason for this is to keep the EDMX files small and manageable while also allowing them to focus on a conceptual set of tables on the database.
Eg
Orders.edmx
Users.edmx
Trades.edmx
These all point to a different set of tables on the same db.
I now need to add the user table to the Trade.edmx file. Since the user table is already in the user.edmx file, this creates the same User type twice under a different namespace which means I would need 2 UserRepository objects.
Common.data.trade.User
Common.data.users.User
Is there a way of avoiding 2 repository objects for the same table?
Any suggestions would be greatly appreciated
If you are using POCO generator you can update template for Trades.edmx to not generate new User class and its context template to use User class from Users namespace. EF matches POCO classes with entities in designer only by the class name (namespace is omitted) so it will work.
The disadvantage is that you have User entity in two mapping files and you must update it in both files or your application throw exception at runtime.
The reason for this problem is your architecture - at the beginning you wanted separated models but know you want to combine entities from different models. Those are contradicting requirements. Either use separated model where Trade knows only userID without any navigation property (like if it is defined in another database) or move all entities to single EDMX to support your new requirements.
Lets say I have Customer, Order, OrderDetail classes in the business layer (It's a simplified version of my problem).
I have also an old (existing) database that has one global table where every row of the table contains the information of Customers-Orders-OrderDetails; for example:
CustomerID, CompanyName,Fax,OrderID, OrderDate,ProductID,UnitPrice,Quantity
(in this way there are duplicated information of a Customer in different rows).
In the future I'll have a new database (with different table Customers, Orders, OrderDetails), and I want to use the same program.
I want to use EF CodeFirst to mapping to the old database and in the future to the new database
Which is the best solution?
Design a business layer with a global class that contains the information of Customers-Orders-OrderDetails. So the mapping of this class
with the old database using EF4 in the data layer is trivial.
In the future I'll modify both business layer and data layer for the new database.
Design a business layer with Customers, Orders, OrderDetails classes. In this case is it possible to map these classes to the global table of the old database? How ? (the problem is that the Customer-Order is one to many).
In the future I'll modify only data layer for mapping the new database.
This will work for now and later you will have to modify everything working with a global class - it can be a lot of work.
It is not possible to map one table to three entities where two have one-to-many relation between them with EF.
Use third approach. Load one class as described in first approach but immediately convert result to three classes from the second approach. The reverse operation will be done in case of persisting changes. Wrap this code in single place - repository. Your application will use three classes and it will not have any knowledge about the way how they are persisted. Once you change the database you will only remove additional conversions from the repository and work directly with Customer, Order, OrderDetail loaded and persisted by EF.
I have database with 3 tables as follows:
From within Visual Web Developer 2010 Express, I create an EF model using Entity Data Model Wizard. I select the 3 tables. Unfortunately, the resulting EF model does not contain the junction table, i.e., QuestionsTags table. The following figure shows the EF model diagram.
My question: Why cannot the Entity Data Model Wizard work for many-many related tables?
This is the difference between physical model and conceptual model. In physical model you use junction able to define M:N relation because relation databases don't support it natively. In conceptual model you do not deal with physical storage. Junction table is not included in conceptual model because it is not needed. You don't need to access it, you need to access Tags related to Questions or Questions related to Tags. Those relations are directly accessible by navigation properties.
Junction table will be automatically added to model only if it contains additional columns (not only FKs to build M:N relation). It is also possible to manually modify (EF4) model and force it to add entity for junction table.
It works. Notice the navigation properties at the bottom of your EF model diagram.
The QuestionsTags table only exists to model the many-to-many relationship in a relational database. When you have objects that don't have to fit into a rigid table schema, you can use a collection on a question object to get all the tags on that question, and likewise, a collection on a tag object to get all the questions with that tag...The Entity Framework models this for you and will populate these collections automatically.
I am currently using LINQ and the Entity Framework to do my database connection layer. In my database I have a Files table and a Products table. I also have a ProductHasFiles table that joins the 2 in a many to many relationship.
My issue is this. I have a single file loaded in my context and I have a list of Product IDs that I need to either attach or detach from to the file record. How do I do that?
I know I can get all of the current Products attached to the File by doing File.Product.Load(); but how do I detach them once I do this? Also, is there a way to attach existing Products without loading the whole Product entry? I already have the ID so I hope that would be enough.
If you want to add or remove object without retrieving it, use stub entities: How to delete an object without retrieving it. Create stub, add to context, add to file.Products.
Why do you want to detach after loading?
I have 2 databases (sql server 2005) in my system, one for configuration data and the other one for Application Data, but there are some tables that are needed in both databases. We've solved that using Synonyms but the problem is when we map the tables in Entity Framework.
We have a Language table in the config database, used for localization purposes. But in the application we have a table called "Countries", and it has a child table to contain the country's fields translated.
My Entity Framework Context maps tables in the Application database and the only way to map the Languages table from the other database is including a View created in the Application Database. Everything works fine, but when I try to make an Association between the CountryTranslation entity and the Language entity I get this exception:
Problem in Mapping Fragments starting at lines 733, 855: Non-Primary-Key column(s) [pai_codlan] are being mapped in both fragments to different conceptual side properties - data inconsistency is possible because the corresponding conceptual side properties can be independently modified.
Do you know if this is a possible scenario? How do I resolve this?
Thx!
Solved!
All I had to do was delete the column that was mapped as a Entity Property and just keep the Navigational Property..