Entity Framework Code FirstエンティティPOCOの主キーであるクラスのプロパティを見つけるにはどうすればよいですか?
Id /クラス名+ "Id"の文字列照合は不適切なオプションであることに注意してください。 Entity Frameworkで使用されている規則を掘り下げて、キープロパティを確実に取得する方法が必要です。
前もって感謝します。
マッピングメタデータにキープロパティの名前を取得するよう要求できます(複数ある場合もあります)。
ObjectContext objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
ObjectSet<YourEntity> set = objectContext.CreateObjectSet<YourEntity>();
IEnumerable<string> keyNames = set.EntitySet.ElementType
.KeyMembers
.Select(k => k.Name);
キー名を取得したら、リフレクションを使用してそれらの値にアクセスできます。
ご覧のとおり、DbContext APIは、メタデータのマッピングなどの詳細に煩わされない単純なシナリオにのみ対応しているため、ObjectContext APIに戻ります。
それが誰かを助ける場合、私は事前に型を知らなくてもこれを行うことができるようにする必要があったので(YourEntity
を知らなかったため、CreateObjectSet<YourEntity>()
を簡単に行うことができませんでした)。 @Ladislavのソリューションを次のように適応させることができました。
// variable "type" is a System.Type passed in as a method parameter
ObjectContext objectContext = ((IObjectContextAdapter)this.context).ObjectContext;
IEnumerable<string> retval = (IEnumerable<string>)objectContext.MetadataWorkspace
.GetType(type.Name, type.Namespace, System.Data.Entity.Core.Metadata.Edm.DataSpace.CSpace)
.MetadataProperties
.Where(mp => mp.Name == "KeyMembers")
.First()
.Value;
MetadataWorkspace.GetType
には、System.Typeの代わりに、タイプ名と名前空間の文字列が必要ですが、それが私が見つけた中で最高です。
EF 6.1には、これを簡単にするDb()
拡張メソッドがあります。
EntityFramework.MappingAPI.Extensions.MappingApiExtensions
例:
public static IEnumerable<string> GetPrimaryKeyPropertyNames(DbContext db, Type entityType)
{
return db.Db(entityType).Pks.Select(x => x.PropertyName);
}
タイプごとのテーブル継承のため、上記の両方のアプローチに問題がありました。私の作業バージョン(@ S'pht'Krのソリューションに基づいていますが、この理由でDataSpace.CSpaceではなくDataSpace.OSpaceを使用しています)は以下のとおりです。
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;
}
ユーザーrashleighpと同様に、コンパイル時に型を知る必要はなく、実行時に型を知るだけでよいユーザーLadislav Mrnkaの回答の変種も必要でした。また、ユーザーrashleighpのように、ユーザーS'pht'Krのソリューションは私にはうまくいきませんでしたが、彼のソリューションはうまくいきました。以下では、この会話に貢献してくれた彼の回答のより単純なバージョンを提供しました。しかし、私はユーザーanjdreasによってソリューションについて学習したばかりであり、それを使用します。
// 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);