C# 使用Linq to Entity中的Func作为泛型方法参数
我想创建基于实体框架的函数,它将更新SQL数据库中的表 此表具有父子关系,因此我正在基于C# 使用Linq to Entity中的Func作为泛型方法参数,c#,entity-framework,linq-to-entities,C#,Entity Framework,Linq To Entities,我想创建基于实体框架的函数,它将更新SQL数据库中的表 此表具有父子关系,因此我正在基于parentID更新子组 我想要一个泛型函数,但我不知道如何从编译时定义未知的对象中获取ID 我尝试使用Func,这可能非常简洁,但它不能用于Linq to实体 代码: protected static void update<TEntity>(DbSet<TEntity> set, int parentID, List<TEntity> entities, Func&
parentID
更新子组
我想要一个泛型函数,但我不知道如何从编译时定义未知的对象中获取ID
我尝试使用Func
,这可能非常简洁,但它不能用于Linq to实体
代码:
protected static void update<TEntity>(DbSet<TEntity> set, int parentID,
List<TEntity> entities, Func<TEntity, bool> isNew, Func<TEntity, int> getID = null,
Func<TEntity, int> getParentID, Action<TEntity, TEntity> updateSingleEntity)
where TEntity : class
{
var currentIDs = entities.Select(e => getID(e));
var newEntities = entities.Where(e => isNew(e));
var existingEntities = entities.Where(e => !isNew(e));
var deletedEntities
= set.Where(e => getParentID(e) == parentID && !currentIDs.Contains(getID(e)));
foreach (var toAdd in newEntities)
{
set.Add(toAdd);
}
foreach (var toDelete in deletedEntities)
{
var entity = set.Find(getID(toDelete));
set.Remove(entity);
}
foreach (var toUpdate in existingEntities)
{
var entity = set.Find(getID(toUpdate));
updateSingleEntity(toUpdate, entity);
}
}
在我看来,这很好。有没有办法实现这样的功能
我做不到(我试过):
具有ID属性的接口可以是整洁的。但是我无法在这个界面中定义
parentID
,因为这个属性的名称在DB中的各个实体中都不同。首先,正如在注释中告诉您的,您需要使用表达式getId
要使用它,不要这样做entities。选择(e=>getID(e))
,而只是选择这个entities。选择(getID)
。原因是Select
需要lamba表达式,而getId
包含lambda表达式。表达式是必需的,因此它是EF工作所必需的表达式树,而不是编译表达式。你可以阅读
对于接口的替代解决方案,您必须按照以下方式实施:
update(set, parentID, someList, e => e.ID != 0, e => e.ID, e => ParentID, somefunc);
public interface IId
{
public int GetId();
}
public int GetId() { return parentId; }
update(set, e => e.ParentID, parentID, someList, e => e.ID, somefunc);
然后,您需要在所有类中实现它,例如:
update(set, parentID, someList, e => e.ID != 0, e => e.ID, e => ParentID, somefunc);
public interface IId
{
public int GetId();
}
public int GetId() { return parentId; }
update(set, e => e.ParentID, parentID, someList, e => e.ID, somefunc);
或
您还应该向通用方法添加接口约束,如下所示:where tenty:class,IId
但是,您会发现两个问题:
您需要为所有实体类型实现GetId
(或者至少对于那些将与thid方法一起使用的实体类型)
无法将GetId
函数转换为表达式树,因此EF不知道如何将其转换为SQL表达式。(我不确定,但它甚至可能会引起错误)
我认为您的函数应该如下所示:
protected static void Update<TEntity>(DbSet<TEntity> set, Expression<Func<TEntity, int>> getParentID, int parentID, List<TEntity> entities, Func<TEntity, int> getID, Action<TEntity, TEntity> updateSingleEntity)
where TEntity : class
{
var filter = Expression.Lambda<Func<TEntity, bool>>(Expression.Equal(getParentID.Body, Expression.Constant(parentID)), getParentID.Parameters[0]);
var targetEntities = set.Where(filter).ToDictionary(getID);
foreach (var entity in entities)
{
var entityID = getID(entity);
TEntity targetEntity;
if (!targetEntities.TryGetValue(entityID, out targetEntity))
set.Add(entity);
else
{
updateSingleEntity(targetEntity, entity);
targetEntities.Remove(entityID);
}
}
if (targetEntities.Count > 0)
set.RemoveRange(targetEntities.Values);
}
Func将不起作用。Use expression我试图使用它,但当我使用它时,出现了以下错误:“getID”是一个“变量”,但它的用法类似于“方法”。声明:表达式getID。用法:getID(toDelete)