19

I have a generic method with type parameter T, where T is the type of entity in EF model. I need to get the name of identifying field in this type. I saw this article: Is there a way to get entity id-field's name by reflection or whatever? But I can't understand, what Tevin talking about when he talks about EntitySetBase and EntityTypeBase types. If EntityTypeBase is type of one of the entities in model, so then EF6 have no property KeyMembers.

Community
  • 1
  • 1
Jonik
  • 1,208
  • 2
  • 12
  • 20
  • take a look at [this post](http://stackoverflow.com/questions/7253943/entity-framework-code-first-find-primary-key) – Yuliam Chandra Aug 05 '14 at 15:07
  • @YuliamChandra thanks for reply. So, **KeyMembers** getting from context and as I understand code creates entity set which use some system resources. Is there other way to get key-field name with reflection? – Jonik Aug 05 '14 at 16:40
  • it's not a pure reflection, it needs to get the key name first using edm that is explained in the post, because the key property can be configured as key field by using [convention](http://msdn.microsoft.com/en-us/data/jj679962.aspx) and [Fluent Api](http://msdn.microsoft.com/en-us/data/jj591617.aspx#1.1), which we can't get by reflection only – Yuliam Chandra Aug 05 '14 at 16:45
  • Anyway, all the data are in DbContext. Is there no other way to get key Name but create ObjectSet with CreateObjectSet() method??? – Jonik Aug 05 '14 at 17:23

1 Answers1

32

I don't think it's possible to get the primary keys only by reflection.

First, let's find out how EF determine which property(ies) that will be primary key(s) regardless of the order / priority

The Entity Framework convention for primary keys is:

  1. Your class defines a property whose name is “ID” or “Id”
  2. or a class name followed by “ID” or “Id”

We can use GetProperties and compare the property name.

var key = type.GetProperties().FirstOrDefault(p => 
    p.Name.Equals("ID", StringComparison.OrdinalIgnoreCase) 
    || p.Name.Equals(type.Name + "ID", StringComparison.OrdinalIgnoreCase));

We can use CustomAttributes and compare the attribute type.

var key = type.GetProperties().FirstOrDefault(p => 
    p.CustomAttributes.Any(attr => attr.AttributeType == typeof(KeyAttribute)));

This is the one that's difficult to do, modelBuilder is encapsulated in the OnModelCreating and even if we save the modelBuilder somewhere as field/property, it's still difficult to extract the key from HasKey function, everything is encapsulated. You can check the source code. And everything in EF depends on ObjectContext and once the ObjectContext is called, for example this line of code,

((IObjectContextAdapter)context).ObjectContext

then a connection to the database will be made, you can check using profiler. And here is the code excerpt of the source code.

public override ObjectContext ObjectContext
{
    get
    {
        Initialize();
        return ObjectContextInUse;
    }
}

public void Initialize()
{
    InitializeContext();
    InitializeDatabase();
}

Therefore, currently the only possible way to get the primary key(s) is through object set, entity set, key members, etc as explained in this post

var keyNames = set.EntitySet.ElementType.KeyMembers.Select(k => k.Name);
Community
  • 1
  • 1
Yuliam Chandra
  • 14,494
  • 12
  • 52
  • 67
  • Great Answer! ... Regarding to [KeyAttribute] ... It's better to use 'Where' instead of 'FirstOrDefault' because some of my entities with Composite Key. – bunjeeb Aug 29 '19 at 17:22