What are Independent Associations and Foreign Key Associations?
Foreign Key Association is where you have a foreign key property in your model in addition to the corresponding Navigation Property. Independent Association is when you have a foreign key column in your database but the foreign key property corresponding to this column is not in your model - i.e. you have a NavigationProperty but there is no foreign key property that would tell you what the ID value of the related property is without actually going to the related property.
Here is an example of a model with an Independent Association (notice that the Dependent does not have a foreign key - just navigation property):
public class Dependent
{
public int Id { get; set; }
[Required]
public Principal PrincipalEntity { get; set; }
}
public class Principal
{
public int Id { get; set; }
public ICollection<Dependent> DependentEntities { get; set; }
}
public class MyContext : DbContext
{
public DbSet<Dependent> Dependents { get; set; }
public DbSet<Principal> Principals { get; set; }
}
And here is an example of the same model but with the ForeignKey Association (notice the PrincipalEntity_Id property and the [ForeignKey()] attribute):
public class Dependent
{
public int Id { get; set; }
public int PrincipalEntity_Id { get; set; }
[Required]
[ForeignKey("PrincipalEntity_Id")]
public Principal PrincipalEntity { get; set; }
}
public class Principal
{
public int Id { get; set; }
public ICollection<Dependent> DependentEntities { get; set; }
}
public class MyContext : DbContext
{
public DbSet<Dependent> Dependents { get; set; }
public DbSet<Principal> Principals { get; set; }
}
Note that your database won't change - the underlying database always had the column for the foreign key but with the independent association it was not exposed.
With foreign key associations you can update the relationship just by changing the value of the foreign key. This is handy if you know the value because you don't need to load the entity you want to update the navigation property to.
Code First: Independent associations vs. Foreign key associations?
If you want to take full advantage of ORM you will definitely use Entity reference:
public class Order
{
public int ID { get; set; }
public Customer Customer { get; set; } // <-- Customer object
...
}
Once you generate an entity model from a database with FKs it will always generate entity references. If you don't want to use them you must manually modify the EDMX file and add properties representing FKs. At least this was the case in Entity Framework v1 where only Independent associations were allowed.
Entity framework v4 offers a new type of association called Foreign key association. The most obvious difference between the independent and the foreign key association is in Order class:
public class Order
{
public int ID { get; set; }
public int CustomerId { get; set; } // <-- Customer ID
public Customer Customer { get; set; } // <-- Customer object
...
}
As you can see you have both FK property and entity reference. There are more differences between two types of associations:
Independent association
- It is represented as separate object in
ObjectStateManager
. It has its ownEntityState
! - When building association you always need entitites from both ends of association
- This association is mapped in the same way as entity.
Foreign key association
- It is not represented as separate object in
ObjectStateManager
. Due to that you must follow some special rules. - When building association you don't need both ends of association. It is enough to have child entity and PK of parent entity but PK value must be unique. So when using foreign keys association you must also assign temporary unique IDs to newly generated entities used in relations.
- This association is not mapped but instead it defines referential constraints.
If you want to use foreign key association you must tick Include foreign key columns in the model in Entity Data Model Wizard.
Edit:
I found that the difference between these two types of associations is not very well known so I wrote a short article covering this with more details and my own opinion about this.
Foreign Key vs. Independent Relationships - is there improvement with Entity Framework 5?
If you have a large model, you're bound to "pollute" your domain objects (or conceptual model in general) anyway. For models with FK-mapped associations, the cost of "view generation" - a stage in the EF processing pipeline necessary to execute queries or save changes, one that can be moved to build-time ("pre-generating views") - is lower compared to models with independent associations. This is important because the amount of time to perform it may be unnoticeable for small models, but it gets longer very fast, especially when there are associations mapped to nullable foreign keys (to-0..1, or to-1 with derived entities in TPH mapped hierarchies). In the official EF5 performance considerations document an example difference in view generation time for a very large model is given as between "over a month and then we gave up" (with independent associations) and 104 minutes (with FK-mapped associations). In my case (several hundred highly connected entities) it's between 25 minutes and 40 seconds. The situation is the same in EF5 as it was in the previous versions.
EF model with code first independent association or foreign key association
My Users table has primary key UserID and Certificates table has PK
CertID and a column UserID which I can say is a foreign key. Just when
I thought its a one to many relationship, I realized that some UserID
in Users table are not found in Certificates table. However all UserID
in Certificates can be found in Users table.
That's pretty normal for a one-to-many relationship where User
is the principal and Certificate
the dependent and you have a constraint enforced for the relationship.
I don't see this as an argument to decide for independent or foreign key associations. As far as I can tell you can map a database schema with both association types. The database schema shouldn't be the driving factor for the decision. Ladislav's posts you have linked explained it in all details. There are other points than the database schema that will guide the decision:
- Architecture: Strict separation of object and relational world which might lead to the decision that you don't want a "foreign key" property as a relational artifact in your object model. This goes in favor of independent associations.
- Ease of use: The additional foreign key property makes it easier to work with relationships, especially updating them, in some scenarios. This point is for foreign key associations.
- Performance: EF is faster with foreign key associations in some situations with larger models.
Personally point 2 above tips the scales for me in most cases, but as said both is possible.
Mapping with foreign key associations (I omit all properties except PK, FK and navigation properties to keep it short):
public class Certificates
{
[Key]
public int CertID { get; set; }
[ForeignKey("User")]
public int UserID { get; set; }
[ForeignKey("Quiz")]
public int QuizID { get; set; }
public Users User { get; set; }
public Quiz Quiz { get; set; }
}
public class Users
{
public int ID { get; set; }
public ICollection<Certificates> Certificates { get; set; }
}
public class Quiz
{
public int QuizID { get; set; }
public ICollection<Certificates> Certificates { get; set; }
}
This assumes that both relationships are required, i.e. FKs in the database are not nullable. If they are you need to make the FK properties nullable as well (int?
). Instead of data annotations you can use Fluent API, similar (but not exactly identical!) to the following example.
Mapping with independent associations:
public class Certificates
{
[Key]
public int CertID { get; set; }
public Users User { get; set; }
public Quiz Quiz { get; set; }
}
public class Users
{
public int ID { get; set; }
public ICollection<Certificates> Certificates { get; set; }
}
public class Quiz
{
public int QuizID { get; set; }
public ICollection<Certificates> Certificates { get; set; }
}
public class cpdContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entitiy<Users>()
.HasMany(u => u.Certificates)
.WithRequired(c => c.User) // or WithOptional
.Map(m => m.MapKey("UserID")); //<- DB FK column name
modelBuilder.Entitiy<Quiz>()
.HasMany(u => u.Certificates)
.WithRequired(c => c.Quiz) // or WithOptional
.Map(m => m.MapKey("QuizID")); //<- DB FK column name
}
}
The navigation properties in Certificates
are not required (neither in the first nor the second example), you can remove them, if you don't need them, just use the parameterless WithRequired()
then, and use Fluent API in the first example. (Possibly a [ForeignKey("UserID")]
annotation on the Certificates
collection in the Users
class will work as well.)
EF4 Independent Associations - Why avoid them?
I think it's personal preference. Originally, EF was created to only use indep. associations and aligned with a more classic ERM approach. However, most of us devs are so dependent on FKs that it made life very complex. So MS gave us FKs in EF4 which meant not only having the FK as a property in the dependent entity but the relationships are defined through constraints in the conceptual model rather than buried in the mappings. There are still a few relationships that you can only define with an indep association: many to many and unique foreign keys. Note that if you are planning to use RIA Services (doesn't sound like it) that RIA only recognizes FK associations.
So if you prefer to leverage the independent associations you still absolutely can use them in EF4. They are totally supported. But as James suggests, there are a few more traps to be aware of...things that you'll need to do more explicitly because of the way EF works with graphs especially. Or that case where you do just want that FK , e.g., you have the ID of a customer but you don't h ave the instance. You could create an order but without that nice CustomerID FK property, you have to do some extra juggling to get that CustomerID in there.
hth
Will one-to-one foreign key associations be supported in EF v-Next?
If "v-Next" is Entity Framework 6, then no, it apparently won't support one-to-one foreign key associations, as you can see on the roadmap for all features planned for EF 6.
You can also see that Unique Constraint support is not on the roadmap and still marked as "Under Review" on UserVoice.
Because a one-to-one foreign key association is basically a one-to-many association with a unique constraint on the foreign key column I would expect that one-to-one FK associations won't be implemented before Unique Constraint support is available. It's especially required if you want that A
is the principal in your two relationships. Currently EF does not support relationships where the principal's key is not the primary key but some column with unique constraint.
In this blog post the feature is described and mentioned that it is "postponed", so let's hope for EF 7.
How to get foreign key value for independent association without hitting database?
It's possible. With your example model you can find the foreign key values the following way:
Bbb bbb = myDbContext.Bbbs.First();
var objectContext = ((IObjectContextAdapter)myDbContext).ObjectContext;
var relMgr = objectContext.ObjectStateManager.GetRelationshipManager(bbb);
var relEnds = relMgr.GetAllRelatedEnds();
var relEnd = relEnds.Single(); // because yor model has exactly one relationship
var entityRef = relEnd as EntityReference<Aaa>;
var entityKey = entityRef.EntityKey;
int foreignKeyValue = (int)entityKey.EntityKeyValues[0].Value;
// to confirm that no database query happened
Console.WriteLine(entityRef.IsLoaded); // outputs false
In the more general case where you have multiple relationships in the Bbb
class and maybe even more than one navigation property refering to Aaa
you need to find the correct element in the relEnds
enumeration. You could also have composite foreign keys. It would look like this then:
Bbb bbb = myDbContext.Bbbs.First();
var objectContext = ((IObjectContextAdapter)myDbContext).ObjectContext;
var relMgr = objectContext.ObjectStateManager.GetRelationshipManager(bbb);
var entityRef = relMgr.GetRelatedReference<Aaa>(
"MyEntityNamespace.Bbb_MyIndependentAssociation",
"Bbb_MyIndependentAssociation_Target");
var entityKey = entityRef.EntityKey;
object[] compositeForeignKeyValues =
entityKey.EntityKeyValues.Select(e => e.Value).ToArray();
// to confirm that no database query happened
Console.WriteLine(entityRef.IsLoaded); // outputs false
Note, that IsLoaded
can be true
if you inspect the entityRef
object in the debugger which can cause the related object to be loaded (even though lazy loading is disabled).
Related Topics
Unity Singleton Manager Classes
Is the Use of Dynamic Considered a Bad Practice
Why Are Unsigned Int's Not Cls Compliant
Accessing Password Protected Network Drives in Windows in C#
Value of Type 'T' Cannot Be Converted To
No Overflow Exception for Int in C#
C# "Parameter Is Not Valid." Creating New Bitmap
Does C# Optimize the Concatenation of String Literals
How to Parse Hex Values into a Uint
Read from Location on Console C#
Why Must I Provide Explicitly Generic Parameter Types While the Compiler Should Infer the Type
How to Limit the Maximum Number of Parallel Tasks in C#
ASP.NET File Download from Server