What Are Independent Associations and Foreign Key Associations

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 own EntityState!
  • 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



Leave a reply



Submit