クラス(主キー値を含む新しいデータが含まれる)に渡すことができる何かを書き、エンティティフレームワークを使用して、主キーを使用してエンティティを取得しようとしています。したがって、主キーの値を含むクラスがありますが、必ずしも主キーを知っているわけではありません (ただし、Entity Framework は知っています)。
(後でエンティティを一般的に更新する必要もありますが、それは別の質問です)
LINQ でこれを行う簡単な方法はありますか?
クラス(主キー値を含む新しいデータが含まれる)に渡すことができる何かを書き、エンティティフレームワークを使用して、主キーを使用してエンティティを取得しようとしています。したがって、主キーの値を含むクラスがありますが、必ずしも主キーを知っているわけではありません (ただし、Entity Framework は知っています)。
(後でエンティティを一般的に更新する必要もありますが、それは別の質問です)
LINQ でこれを行う簡単な方法はありますか?
私が理解しているように、コンテキストによって追跡されていないオブジェクトがあり、EFを使用してデータベース内の同等のエンティティを照会したいとします。(次に、オブジェクトの値でデータベースを更新する必要がありますが、それは別の質問になります。)
主キーの値がわかっている場合は、Findメソッドを使用してデータベースからエンティティを取得できます。トリッキーな点は、一般的な方法で主キー値を取得することです。これは、EFの将来のバージョンで簡単にしたいことですが、今のところ、役立ついくつかの拡張メソッドを作成しました。
まず、特定のタイプの主キー名を取得しましょう。これはトリッキーなビットです。ObjectContextにドロップダウンし、MetadataWorkspaceを使用する必要があります。
public static IEnumerable<string> PrimayKeysFor(
this DbContext context,
object entity)
{
Contract.Requires(context != null);
Contract.Requires(entity != null);
return context.PrimayKeysFor(entity.GetType());
}
public static IEnumerable<string> PrimayKeysFor(
this DbContext context,
Type entityType)
{
Contract.Requires(context != null);
Contract.Requires(entityType != null);
var metadataWorkspace =
((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace;
var objectItemCollection =
(ObjectItemCollection)metadataWorkspace.GetItemCollection(DataSpace.OSpace);
var ospaceTypes = metadataWorkspace.GetItems<EntityType>(DataSpace.OSpace);
var ospaceType = ospaceTypes
.FirstOrDefault(t => objectItemCollection.GetClrType(t) == entityType);
if (ospaceType == null)
{
throw new ArgumentException(
string.Format(
"The type '{0}' is not mapped as an entity type.",
entityType.Name),
"entityType");
}
return ospaceType.KeyMembers.Select(k => k.Name);
}
}
これで、これを利用して特定のエンティティ(追跡する必要がない)のキー値を取得する拡張メソッドを追加できます。
public static object[] PrimayKeyValuesFor(this DbContext context, object entity)
{
Contract.Requires(context != null);
Contract.Requires(entity != null);
var entry = context.Entry(entity);
return context.PrimayKeysFor(entity)
.Select(k => entry.Property(k).CurrentValue)
.ToArray();
}
これができたら、Findを使用して、オブジェクトについて何も知らなくても、特定のオブジェクトに対応するデータベース内のエンティティを取得するのは非常に簡単です。例えば:
var databaseOrderLine =
context.Set<OrderLine>().Find(context.PrimayKeyValuesFor(orderLine));
一般的な ContextHelper を使用できます。
public class ContextHelper<T> : IContextHelper<T>
{
//Instantiate your own EntityFrameWork DB context here,
//Ive called the my EntityFramework Namespace 'EF' and the context is named 'Reporting'
private EF.DataContext DbContext = new EF.DataContext();
public bool Insert<T>(T row) where T : class
{
try
{
DbContext.Set<T>().Add(row);
DbContext.SaveChanges();
return true;
}
catch(Exception ex)
{
return false;
}
}
public bool Update<T>(T row) where T : class
{
try
{
DbContext.Set<T>().AddOrUpdate(row);
DbContext.SaveChanges();
return true;
}
catch (Exception ex)
{
return false;
}
}
public bool Delete<T>(T row) where T : class
{
return Update(row); //Pass an entity with IsActive = false and call update method
}
public bool AddRows<T>(T[] rows) where T : class
{
try
{
DbContext.Set<T>().AddOrUpdate(rows);
return true;
}
catch (Exception ex)
{
return false;
}
}
}
これを使用して呼び出します:
public void NewEmailRecipient(EF.EmailRecipient recipient)
{
// logic operation here
EntityToDB(recipient);
}
public void NewReportRecipient(EF.ReportRecipient recipient)
{
// logic operation here
EntityToDB(recipient);
}
public void UpdateEmailRecipient(EF.EmailRecipient recipient)
{
// logic operation here
UpdateEntity(recipient);
}
public void UpdateReportRecipient(EF.ReportRecipient recipient)
{
// logic operation here
UpdateEntity(recipient);
}
// call generic methods to update DB
private void EntityToDB<T>(T entity) where T : class
{
var context = new ContextHelper<T>();
context.Insert(entity);
}
private void UpdateEntity<T>(T entity) where T : class
{
var context = new ContextHelper<T>();
context.Update(entity);
}
ここにデモソリューションを投稿しました
https://github.com/andyf1ynn/EntityFramwork-Generic-Type-DAL