我正在尝试编写一些可以传入类的东西(其中将包括新数据,包括主键值)并使用实体框架,使用主键检索实体。所以,我有一个类,包括主键值,但我不一定知道主键(但 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