From June 2008, the whole EF4 design process is transparent to us in the EF Design blog. During the process, many great features are newly added including the Foreign Key (FK) Association. Whether FKs are important in the conceptual model has been talked. Every coin has two sides and the feedback just indicated it. Some customers are defenders for FKs while others think FKs destroy the conceptual model. Fortunately, EF team decided to provide both the options in EF4. Now we can either use the new FK Association to gain all the benefit having FKs in the entities, or still use the .NET 3.5 SP1 style Association.

What’s the FK Association?

Like we have FKs in LINQ to SQL, thanks to FK Association in EF4, by default the FK properties are kept in the entities along with the navigation properties, so the relationships can be set either by the FK properties or by the original navigation properties. While in .NET 3.5 SP1, the FK columns are removed from the entities, which makes the old style that is called Independent Association.

How to use the FK Association? (Designer)

This is what we have in the database. It’s a very simple model. Please note Course table has a FK to the Department table.

 

image

What we have in EF4:

image

Note that “Include foreign key columns in the model” is checked by default. So the FK columns will be together with the navigation properties.

image

Then double click the association, we see the FK Association properties window. Note that we don’t have such a window in VS2008.

image

 

Certainly, if we uncheck the “Include foreign key columns in the model” in the Entity Data Model Wizard, we get the Independent Association with only the navigation properties.

image

 

Let’s open the .edmx via XML (Text) Editor to see the XML metadata difference of the two associations.

The FK Association in CSDL:

  1: <Association Name="FK_Course_Department">
  2:     <End Role="Department" Type="FKAssociationModel.Department" Multiplicity="0..1" />
  3:     <End Role="Course" Type="FKAssociationModel.Course" Multiplicity="*" />
  4:     <ReferentialConstraint>
  5:       <Principal Role="Department">
  6:         <PropertyRef Name="DepartmentID" />
  7:       </Principal>
  8:       <Dependent Role="Course">
  9:         <PropertyRef Name="DepartmentID" />
 10:       </Dependent>
 11:     </ReferentialConstraint>
 12:   </Association>
 13: 

 

The Independent Association in CSDL:

  1: <Association Name="FK_Course_Department">
  2:   <End Role="Department" Type="IndependentAssociationModel.Department" Multiplicity="0..1" />
  3:  <End Role="Course" Type="IndependentAssociationModel.Course" Multiplicity="*" />
  4: </Association>
  5: 

Same as what we do in VS2008, the associations can be directly added in the designer. But the difference is the Add Association dialog. Right click the entity, Add à Association:

EF4 (VS2010)

image

 

EF 3.5 (VS2008)

image

 

Please note that the two kinds of associations can be in the same model.

 

How to use the FK Association? (Codes)

Now let’s write some codes to test the two kinds of associations.

FK Association to add new related entities

  1: /// <summary>
  2:         /// Insert a new Course and its Department entity by Foreign Key 
  3:         /// Association
  4:         /// </summary>
  5:         private static void InsertNewRelatedEntities()
  6:         {
  7:             using (FKAssociationEntities context = 
  8:                 new FKAssociationEntities())
  9:             {
 10:                 // Create a new Department entity.
 11:                 Department department = new Department()
 12:                 {
 13:                     DepartmentID = 5, 
 14:                     Name = "Computer Science",
 15:                     Budget = 400000,
 16:                     StartDate = DateTime.Now
 17:                 };
 18: 
 19:                 // Create a new Course entity.
 20:                 Course course = new Course()
 21:                 {
 22:                     CourseID = 5001,
 23:                     Title = "Operation System",
 24:                     Credits = 4,
 25:                     StatusID = true,
 26:                     // Set its foreign key property.
 27:                     DepartmentID = department.DepartmentID
 28:                 };
 29: 
 30:                 try
 31:                 {
 32:                     // Add the Department and Course entities into the 
 33:                     // ObjectContext.
 34:                     context.AddToDepartments(department);
 35:                     context.AddToCourses(course);
 36:                     
 37:                     // Note: The navigation properties between the 
 38:                     // Department and Course entities won't map to each 
 39:                     // other until after SaveChanges is called.
 40:                     context.SaveChanges();
 41:                 }
 42:                 catch (Exception ex)
 43:                 {
 44:                     Console.WriteLine(ex.Message);
 45:                 }
 46:             }
 47:         }
 48: 

 

Note that we need to add both the entities to the ObjectContext by .AddTo***() method, because until .SaveChanges() is called, the relationship (navigation properties) between Department and Course has not been set yet.

 

FK Association to add relationship between a new entity and an existing entity

  1: /// <summary>
  2:         /// Insert a new Course and set it belong to an existing Department 
  3:         /// by Foreign Key Association
  4:         /// </summary>
  5:         private static void InsertByExistingEntities()
  6:         {
  7:             using (FKAssociationEntities context = 
  8:                 new FKAssociationEntities())
  9:             {
 10:                 // Create a new Course entity.
 11:                 Course course = new Course()
 12:                 {
 13:                     CourseID = 5002,
 14:                     Title = "Data Structure",
 15:                     Credits = 3,
 16:                     StatusID = true,
 17:                     // Set the foreign key property to an existing 
 18:                     // Department's DepartmentID.
 19:                     DepartmentID = 5
 20:                 };
 21: 
 22:                 try
 23:                 {
 24:                     // Add the Course entity into the ObjectContext.
 25:                     context.AddToCourses(course);
 26: 
 27:                     // Note: The navigation property of the Course
 28:                     // won't map to the Department entity until 
 29:                     // after SaveChanges is called.
 30:                     context.SaveChanges();
 31:                 }
 32:                 catch (Exception ex)
 33:                 {
 34:                     Console.WriteLine(ex.Message);
 35:                 }
 36:             }
 37:         }
 38: 

 

Also, until .SaveChanges() is called, the relationship (navigation properties) between Department and Course has not been set yet, so we still need to call .AddTo***() method to add the new entity into the ObjectContext.

 

Independent Association to add new entities

  1: /// <summary>
  2:         /// Insert a new Course and its Department entity by Independent 
  3:         /// Association
  4:         /// </summary>
  5:         private static void InsertNewRelatedEntities()
  6:         {
  7:             using (IndependentAssociationEntities context = 
  8:                 new IndependentAssociationEntities())
  9:             {
 10:                 // Create a new Department entity.
 11:                 Department department = new Department()
 12:                 {
 13:                     DepartmentID = 6,
 14:                     Name = "Software Engineering",
 15:                     Budget = 300000,
 16:                     StartDate = DateTime.Now
 17:                 };
 18: 
 19:                 // Create a new Course entity.
 20:                 Course course = new Course()
 21:                 {
 22:                     CourseID = 6001,
 23:                     Title = "Object Oriented",
 24:                     Credits = 4,
 25:                     StatusID = true,
 26:                     // Set the navigation property.
 27:                     Department = department
 28:                 };
 29: 
 30:                 try
 31:                 {
 32:                     // Note: Only need to add one entity because the 
 33:                     // relationship and related entity will be added
 34:                     // automatically.
 35:                     context.AddToCourses(course);
 36: 
 37:                     context.SaveChanges();
 38:                 }
 39:                 catch (Exception ex)
 40:                 {
 41:                     Console.WriteLine(ex.Message);
 42:                 }
 43:             }
 44:         }
 45: 

 

Like in .NET 3.5 SP1, we set the navigation property to build the relationship. Only one of the AddTo***() methods are needed here because the relationship will help us add both the entities into the ObjectContext.

 

Independent Association to add relationship between a new entity and an existing entity

  1: /// <summary>
  2:         /// Insert a new Course and set it belong to an existing Department 
  3:         /// by Independent Association
  4:         /// </summary>
  5:         private static void InsertByExistingEntities()
  6:         {
  7:             using (IndependentAssociationEntities context = 
  8:                 new IndependentAssociationEntities())
  9:             {
 10:                 // Create a new Course entity.
 11:                 Course course = new Course()
 12:                 {
 13:                     CourseID = 6002,
 14:                     Title = ".NET Framework",
 15:                     Credits = 4,
 16:                     StatusID = true,
 17:                     // Set the navigation property to an existing Department 
 18:                     // entity.
 19:                     Department = context.Departments.Single(
 20:                         d => d.DepartmentID == 6)
 21:                 };
 22: 
 23:                 try
 24:                 {
 25:                     // Note: No need to add the Course entity into the 
 26:                     // ObjectContext because it is automatically done by
 27:                     // relating to an existing Department entity.
 28:                     context.SaveChanges();
 29:                 }
 30:                 catch (Exception ex)
 31:                 {
 32:                     Console.WriteLine(ex.Message);
 33:                 }
 34:             }
 35:         }
 36: 

 

Note that we don’t need to call any AddTo***() method here since the relationship is built on an existing entity and it will automatically add the new entity into the ObjectContext.

 

For more detailed sample codes, please refer to the samples CSEFForeignKeyAssociation (C#) and VBEFForeignKeyAssociation (VB.NET) in All-In-One Code Framework which is an open-source project delineating the framework and skeleton of Microsoft development techniques.

 

Additional references

http://msdn.microsoft.com/en-us/library/ee373856%28VS.100%29.aspx
http://blogs.msdn.com/adonet/archive/2009/11/06/foreign-key-relationships-in-the-entity-framework.aspx