How to get primary key value with Entity Framework Core

entity-framework entity-framework-core primary-key repository-pattern

Question

We are currently using the method below which depends upon IObjectContextAdapter in an abstract Repository. From what I'm reading, it appears that anything related to ObjectContext is being chopped out of Entity Framework Core. The method below is the only place we depend upon anything related to ObjectContext.

We'd like to upgrade to Entity Framework Core. This is our only road block. Is there a way to get the value of the primary key of an entity with the Entity Framework Core apis?

// Entity Framework
public virtual int GetKey(T entity)
{
    var oContext = ((IObjectContextAdapter)_DbContext).ObjectContext;
    var oSet = oContext.CreateObjectSet<T>();
    var keyName = oSet.EntitySet.ElementType
                                .KeyMembers
                                .Select(k => k.Name)
                                .Single();

    return (int)entity.GetType().GetProperty(keyName).GetValue(entity, null);
}
1
17
12/7/2017 4:13:26 PM

Accepted Answer

I also faced with similar problem and found the following solution

// Entity Framework Core
public virtual int GetKey<T>(T entity)
{
    var keyName = Context.Model.FindEntityType(typeof (T)).FindPrimaryKey().Properties
        .Select(x => x.Name).Single();

    return (int)entity.GetType().GetProperty(keyName).GetValue(entity, null);
}
31
12/7/2017 4:14:25 PM

Popular Answer

At least in EF Core 2.1 you can get the key this way:

var entry = dbContext.Entry(entity);
object[] keyParts = entry.Metadata.FindPrimaryKey()
             .Properties
             .Select(p => entry.Property(p.Name).CurrentValue)
             .ToArray();

This allows you to get the key which is created as a shadow property.

I do not know how performant is the call Property(p.Name).CurrentValue, nevertheless it is still possible to cache the names of properties of the key:

private static readonly ConcurrentDictionary<Type,string[]> KeyPropertiesByEntityType = new ConcurrentDictionary<Type, string[]>();

public object[] KeyOf<TEntity>(TEntity entity) where TEntity : class
{
    Guard.ArgumentNotNull(entity, nameof(entity));

    var entry = _dbContext.Entry(entity);
    var keyProperties = KeyPropertiesByEntityType.GetOrAdd(
        entity.GetType(),
        t => entry.Metadata.FindPrimaryKey().Properties.Select(property => property.Name).ToArray());

    var keyParts = keyProperties
        .Select(propertyName => entry.Property(propertyName).CurrentValue)
        .ToArray();

    return keyParts;
}

public TKey KeyOf<TEntity, TKey>(TEntity entity) where TEntity : class
{
    var keyParts = KeyOf(entity);
    if (keyParts.Length > 1)
    {
        throw new InvalidOperationException($"Key is composite and has '{keyParts.Length}' parts.");
    }

    return (TKey) keyParts[0];
}


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow