web-dev-qa-db-fra.com

Code Entity Framework en premier. Trouver la clé primaire

Comment trouver quelle propriété d'une classe est la clé primaire du POCO d'entité Entity Framework Code First?

Veuillez noter que la correspondance de chaîne pour l'ID/le nom de la classe + "Id" est une mauvaise option. Il doit exister un moyen d'extraire la convention utilisée par Entity Framework et d'obtenir de manière fiable la propriété de clé.

Merci d'avance.

34
Sleeper Smith

Vous pouvez demander aux métadonnées de mappage d'obtenir les noms des propriétés clés (il peut y en avoir plusieurs):

ObjectContext objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
ObjectSet<YourEntity> set = objectContext.CreateObjectSet<YourEntity>();
IEnumerable<string> keyNames = set.EntitySet.ElementType
                                            .KeyMembers
                                            .Select(k => k.Name);

Une fois que vous avez des noms de clés, vous pouvez utiliser la réflexion pour accéder à leurs valeurs.

Comme vous pouvez le voir, l'approche revient à l'API ObjectContext car l'API DbContext est uniquement destinée aux scénarios simples où vous ne vous souciez pas de détails tels que le mappage de métadonnées.

60
Ladislav Mrnka

Dans EF 6.1, il existe une méthode d'extension Db() qui facilite cette opération.

Exemple:

public static IEnumerable<string> GetPrimaryKeyPropertyNames(DbContext db, Type entityType)
{
    return db.Db(entityType).Pks.Select(x => x.PropertyName);
}
14
angularsen

J'ai eu un problème avec les deux approches ci-dessus en raison de l'héritage de table par type. Ma version de travail (basée sur la solution de @ S'pht'Kr mais utilisant DataSpace.OSpace et non DataSpace.CSpace pour cette raison) est ci-dessous:

        protected IEnumerable<string> GetKeyPropertyNames()
        {
            var objectContext = ((System.Data.Entity.Infrastructure.IObjectContextAdapter) this.Context).ObjectContext;

            return GetKeyPropertyNames(typeof (TEntity), objectContext.MetadataWorkspace);
        }

        private static IEnumerable<string> GetKeyPropertyNames(Type type, MetadataWorkspace workspace)
        {
            EdmType edmType;

            if (workspace.TryGetType(type.Name, type.Namespace, DataSpace.OSpace, out edmType))
            {
                return edmType.MetadataProperties.Where(mp => mp.Name == "KeyMembers")
                    .SelectMany(mp => mp.Value as ReadOnlyMetadataCollection<EdmMember>)
                    .OfType<EdmProperty>().Select(edmProperty => edmProperty.Name);
            }

            return null;
        }
9
rashleighp

Comme l'utilisateur rashleighp, je voulais également une variante de la réponse de l'utilisateur Ladislav Mrnka qui n'a besoin que de connaître le type au moment de l'exécution au lieu d'avoir besoin de connaître le type au moment de la compilation. Tout comme l'utilisateur rashleighp, la solution de l'utilisateur S'pht'Kr n'a pas fonctionné pour moi, mais sa solution a fonctionné. Ci-dessous, je contribue à cette conversation en fournissant une version plus simple de sa réponse qui a fonctionné pour moi. Cependant, je viens d'apprendre la solution par l'utilisateur anjdreas et c'est celle que j'utiliserai.

// variable "type" is a System.Type passed in as a method parameter
((IObjectContextAdapter)context)
    .ObjectContext
    .MetadataWorkspace
    .GetItem<EntityType>(type.FullName, DataSpace.OSpace)
    .KeyProperties
    .Select(p => p.Name);
3
Tyson Williams