Search code examples
c#.netentity-frameworkentity-framework-6ef-model-first

(EF6 Model first) How can I get the value of a foreign key without accessing the navigation property so that I don't need to load the full entity?


How can I get the value of a foreign key without accessing the navigation property so that I don't need to load the full entity?

public class A
{
   public int Id {get;set;}
   // ...
}
public class B
{
   public virtual A A {get;set;}
   // ...
}
int idOfA = MyB.A.Id;   // slow way of doing it.

I'm using Entity Framework 6 ModelFirst+DbContext in VS2012. Previously I used an old EF Version+ModelFirst+ObjectContext. I have bitten the bullet and migrated by creating the model from the old database.

Getting the entity key was possible with the old ObjectContext:

EntityReference<EntityType> reference = MyB.AReference; // AReference was generated by EF
int id = (int)reference.EntityKey.EntityKeyValue[0].Value;

But now the code generator no longer generates EntityReferences for each One or ZeroOrOne navigation property.

So how can I get the foreign key in EF6+DbContext?

Here are some ideas of what I tried/could do but failed/didn't want:

  1. I could just ignore the bad performance and load the full entity to get its primary key.
  2. Using the [ForeignKey]attribute or EF's Fluent API. But I don't know how I can or if I should do that. Maybe it doesn't even work with a model first approach, because "OnModelCreated" isn't called.
  3. I modify the database-entity mapping (the xml stuff in the edmx code) so that for each foreign key an additional property (public int *Id {get;set;}) will be mapped. But I never did that and don't know where to start reading.
  4. When I created the first EF 6.0 model from my old database, there was an option "Include foreign key columns in the model". I didn't activate that last time, which in hindsight was wrong. But doing it again would be a lot of work (manually setting entity inheritance, etc.).
  5. Using the relationship manager. But my generated entities no longer seem to implement the IEntityWithRelationships interface. Even though I think I satisfy the conditions for proxies and I checked in the debugger that proxies classes are created. (edit: Someone else had a similar problem with IEntityWithRelationships+IEntitiyWithChangeTracker. See solution in the comments of this question.)

Solution

  • Here's the code that I use (granted it's not Model First, but there's nothing specific in it to either approaches). In the sample I have products, and to each product belongs a category. Here's how I can query the CategoryId in a Product entity wihtout loading the Category:

    Model1 context = new Model1();
    var product = context.Products.First();
    RelationshipManager relMgr = ((IObjectContextAdapter)context).ObjectContext.ObjectStateManager.GetRelationshipManager(product);
    IEnumerable<IRelatedEnd> relEnds = relMgr.GetAllRelatedEnds();
    IRelatedEnd relEnd = relEnds.Where(r => r.RelationshipName.EndsWith("Product_Category")).Single();
    EntityReference<Category> entityRef = relEnd as EntityReference<Category>;
    var entityKey = entityRef.EntityKey;
    int categoryId = (int)entityKey.EntityKeyValues[0].Value;