I am using EF5 and when the the relationship is 1:N, if I want to load related entities I do the following:
With T-SQL I load from database the main entities with a T-SQL like that:
select *
from MainEntities
where ...
with T-SQL I load the related entities
select *
from RelatedEntities
where IDMainEntity IN (---)
At this point EF populate the property navigation of the main entities with the related entities. Also, in the local property of the type of each entity in the dbContext I have all the entities of each type.
However, if i do the same with a N:N relationship, I don't have the entity of the middle table of the relation, and when I execute the queries I have in the local of the dbContext the entities of each type, but the property navigation is not populated.
I would like to know why and if it exists some alternative.
I use this way because I want to use T-SQL for create dynamic queries. If I use eager loading I don't have the same flexibility to dynamic queries than when I use TSQL, and it is less efficient. If I use explicit loading I to do N additional queries, one of each record in the results of the main entity With my way, I only one additional query, because I get all the related entities at once. If I use lazy loading I have the same problem, N additional queries.
Why EF does not populate the related properties when the relation is N:N?
Thanks.
The feature you are talking about is called Relationship Span or Relationship Fixup and indeed - as you have noticed - it does not work for many-to-many relationships. It only works if at least one end of the association has multiplicity 1 (or 0..1), i.e. it works for one-to-many or one-to-one relationships.
Relationship Span relies on an entity having a foreign key. It doesn't matter if it has an explicit foreign key property (foreign key association) or only a foreign key column in the corresponding database table without a property in the model (independent association). In both cases the FK value will be loaded into the context when the entity gets loaded. Based on this foreign key value EF is able to figure out if a related entity that has the same primary key value as this FK value is attached to the context and if yes, it can "fixup the relationship", i.e. it can populate the navigation properties correctly.
Now, in a many-to-many relationship both related entities don't have a foreign key. The foreign keys are stored in the link table for this relationship and - as you know - the link table does not have a corresponding model entity. As a result the foreign keys will never be loaded and therefore the context is unable to determine which attached entities are related and cannot fixup the many-to-many relationship and populate the navigation collections.
The only LINQ queries where EF will support you to build the correct object graph with populated navigation collections in a many-to-many relationship are eager loading...
var user = context.Users.Include(u => u.Roles).First();
...or lazy loading...
var user = context.Users.First();
var rolesCount = user.Roles.Count();
// Calling Count() or any other method on the Roles collection will fill
// user.Roles via lazy loading (if lazy loading is enabled of course)
...or explicit loading with direct assignment of the result to the navigation collection:
var user = context.Users.First();
user.Roles = context.Entry(user).Collection(u => u.Roles).Query().ToList();
All other ways to load the related entities - like projections, direct SQL statements or even explicit loading without assignment to the navigation collection, i.e. using .Load() instead of .Query().ToList() in the last code snippet above - won't fixup the relationship and will leave the navigation collections empty.
If you intend to perform mainly SQL queries rather than LINQ queries the only option I can see is that you write your own relationship management. You would have to query the link table in addition to the tables for the two related entities. You'll probably need a helper type (that is not an entity) and collection that holds the two FK column values of the link table and probably a helper routine that fills the navigation collections by inspecting the primary key values of the entities you find as attached in the DbSet<T>.Local collections and the FK values in the helper collection.
To add on #Slauma answer:
I faced the same problem recently, getting frustrated that the navigation property is not being set after calling Query().Where().Load(), although I can see that the objects are loaded into the DbContext.
I needed the collection to be part of my main object and use it as you would any other navigation property and not just manage a separate collection, so I did this:
project.Labels = this.Context
.Entry (project)
.Collection (p => p.Labels)
.Query ()
.Where (l => l.CreateUserName == this.UserId)
.ToList();
The problem with this is that EF thinks I added new relationships, which I can't blame it, but it is not what I wanted. As a result, when trying to save the Project object I got an exception when EF tried to insert the relationship into the link table because a row with the same key (projectId + labelId) already exists.
So, the final was to reset the state of the relationships between the project and the labels:
foreach (Label l in project.Labels)
{
((System.Data.Entity.Infrastructure.IObjectContextAdapter)this.Context.AsDbContext ()).ObjectContext.ObjectStateManager.ChangeRelationshipState<Project> (project, l, p => p.Labels, EntityState.Unchanged);
}
After that I was able to use the Labels property just like any other navigation property, not caring that behind the scenes it's a many-to-many relationship.
Related
I'm currently investigating the possibility to use table splitting with EF to stop pulling too many columns for nothing. As for now, I'm able to create a new entity, cut/paste the fields into the sub-entity and map it without much problems.
However, if one of those fields is a FK in the master table, it gives me the following error
"Running transformation: There is no property with name 'IdDocumentImportSource' defined in type referred by Role 'DocumentImports'."
I do understand that the both tables have a NavigationProperties that cannot be resolved anymore by the association FK because the field has been moved to the child table.
Here's my question; Is there a way to automaticaly move the association FK to the child table? I could only make it work by manually deleting the association, both navigation properties, creation the association FK of the child. It involves quite a lot of work on my part if I have to do all this manually for every association FK I got...!
DocumentImports is the ParentTable that I splitted into a new child table DocumentImports_StatusDetail and DocumentImportSources is the table being referenced by the FK.
Thanks!
I use code first of Entity framework. There are two classes "Question" and "User". I defined a relationship as below:
this.HasRequired(v => v.Creator).WithMany(v => v.Questiones)
.HasForeignKey(v => v.CreatorId).WillCascadeOnDelete(false);
After gernerating the database I found that it always create foreign key between Id of User and CreatorId of Question. Because of lower performance of FK(and other reason),I want to define navigation property relationship without setting foreign key in database? Delete FK after EF created it?
If cannot do this using fluent api, could you tell me why EF designed in this way please?
About the lower performance of FK. I have a User table with 5 Million records in it. when I insert a Question into db, since the db check the question.CreatorId validation from User table, it always slower than without FK.
And there are many other reasons that I need to remove FK.
I think I am somewhat obsession because I think that deleting FK after created it is strangely and ugly. What i want is implementing this by using something like WithoutForeignKey in fluent api:
this.HasRequired(v => v.Creator).WithMany(v => v.Questiones)
.WithoutForeignKey(v => v.CreatorId).WillCascadeOnDelete(false);
Without questioning why are you trying to do this strange thing and going just to the answer: you could delete fk constraint after generated, or you could use migrations and remove FK generation from the migration code.
SQL code generated when traversing nav properties will work even if fk constraint doesn't exist, except for cascade deleting
If you want a relationship between two tables, you need to define a foreign key. No way around it. Even if you use Map() in fluent api, you can only hide the foreign key in your model, in the background EF will still use it and it will exist in the database.
Also I don't get what you mean by "performance" of foreign key? One extra (likely small) column won't make a difference. If you mean the navigation properties for the performance part, you can do 3 things:
Don't include them in your model
Make them non-virtual to disable lazy loading
Disable lazy loading all together with ctx.Configuration.LazyLoadingEnabled = false;
If you don't want to tell db about relation and treat both entities as not related (I wonder why), then just ignore these navigation properties and FK field. Note that you will be responsible for managing related entities: saving and loading them from db, updating ids etc
this.Ignore(q => q.Creator);
this.Ignore(q => q.CreatorId);
And you also need to ignore other side of relation, otherwise EF will generate FK column with default name Creator_CreatorId. So in Creator entity configuration:
this.Ignore(c => c.Questiones);
Here's my question. I have 2 models (Person, Event) and with EF and modelbuilder I generate a booking table (with IdPerson and IdEvent as properties).
So in my DB it's correct, I have 3 tables (Person, Event and Booking) with many to many relationship. But I have only 2 models in Visual Studio (Booking doesn't exist because of the self-generated table).
With my Controller I want to write an action for the Person to suscribe to an event and I have to write on my table Booking on the DB but it doesn't exist as a model so I can't do that .
How should I proceede?
Should I create a Booking model and delete my modelbuilder?
When you are using ORMs like EF, you can sit back and let the ORM manage these middle tables.
You can use
person.Events.Add(event)
or
event.People.Add(event)
and EF handles all and inserts a row with personId and eventId in that table.
Here you can find a complete sample:
http://blogs.msdn.com/b/wriju/archive/2011/05/14/code-first-ef-4-1-building-many-to-many-relationship.aspx
I assume this is a model first approach.
The reason for having only 2 objects is that, by default, EF does not create objects for joint tables. What it does create is Navigation Property (Entity Framework - Navigation Property Basics). In one-to-many scenario, a navigation property inside a parent object contains a collection of entities in a foreign / child table. In many-to-many scenario, navigation properties of each entities will simply contain collections of its other entities.
I have an entity that maps to a table called Rule. The table for this entity has an FK to another Table called Category. I'm trying to figure out how to pull in a property from Category in my Rule entity. I'm pretty sure I want to use a join in my entity mapping, but I can't figure out how to configure it so that it works. Here is my mapping:
Join("Category", x =>
{
x.Map(i => i.CategoryName, "Name");
x.KeyColumn("CategoryId");
x.Inverse();
});
Here is the SQL that it's generating...
SELECT ...
FROM Rule rules0_ left outer join Category rules0_1_ on rules0_.Id=rules0_1_.CategoryId
WHERE ...
Here is the SQL that I want.
SELECT ...
FROM Rule rules0_ left outer join Category rules0_1_ on rules0_.CategoryId=rules0_1_.Id
WHERE ...
I can't seem to find anything on the JoinPart that will let me do this. Subselect looks promising from the little bit of documentation I've found, but I can't find any examples of how to use it. Any advice on this problem would be much appreciated. Thanks!
"Join" is poorly named. a "join" in an NHibernate mapping implies a zero-to-one relationship based on a relation of the primary keys of the two tables. You would use a join if, for instance, you had a User table and a UserAdditionalInfo table, with zero or one record per User. The UserAdditionalInfo table would likely reference the PK from User as both a foreign key and its own primary key. This type of thing is common when a DBA has to religiously maintain a schema for a legacy app, but a newer app needs new fields for the same conceptual record.
What you actually need in your situation is a References relationship, where a record has a foreign key relationship to zero or one other records. You'd set it up fluently like so:
References(x=>Category)
.Column("CategoryId")
.Inverse()
.Cascade.None();
The problem with this is that Category must now be mapped; it is a separate entity which is now related to yours. Your options are to live with this model, to "flatten" it by making the entity reference private, changing the mapping to access the entity as such, and coding "pass-throughs" to the properties you want public, or by using a code tool like AutoMapper to project this deep domain model into a flat DTO at runtime for general use. They all have pros and cons.
Pardon the massive headline.
I'm in the situation of having to build an application on top of a database, that I cannot make any changes to. The database does not have any primary- or foreignkeys set.
I'm using linq-2-sql, and I'm interested in having some properties exposed on the entities generated from my dbml. For instance, in the hypothetical example of a one-to-many relationship between table education and student - where each student record has a reference to an education id, I'd like to be able to go:
var student = GetAStudentFromContextOrWhatever();
var studentsEducation = student.Education;
It is my experience, that this kind of property is automatically generated when I drag'n'drop tables with foreignkey relationships from the server explorer.
However as previously mentioned, in this case I do not have these foreign key relationships - rather I am adding the relationships manually in the dbml file, specifying parent and child class.
When I add these relationships, I expect the involved entities in the designer.cs of my context to get populated with properties of a kind like those described above.
This, however, does not happen.
What must I do for my dbml to create these properties for me - based on these manually mapped associations between entities/tables that, on a database level, do not have foreign key associations?
Cheers!
L2S is just that Linq-to-SQL. If it isn't in SQL it won't be generated. The expression trees behind L2S just can't understand what you are doing. The place for your association is in a partial class file which you will have create manually. Also it probably won't update or insert through the association.
I know this is a very old question, but I just ran into the same problem. In order for the relationship in the DBML designer to automatically create the association properties for you, you need to have primary keys on your objects. If you click the column name in the designer, you'll see that your PK field has PrimaryKey = false. Switch that to True and build; all should be well.
Patrick