我想基于Entity Framework创建函数,它将更新SQL数据库中的Table。
此表具有父子关系,因此我根据parentID
更新了一堆子项。
我想拥有一个泛型函数,我不知道如何从编译时未知定义的对象中获取ID。
我尝试使用Func
这可能非常简洁,但它不能在Linq-To-Entities中使用。
代码:
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);
}
}
我想像这样使用这个函数:
update(set, parentID, someList, e => e.ID != 0, e => e.ID, e => ParentID, somefunc);
这是非常整洁的IMO。有没有办法实现这样的功能?
我做不到(我试过):
具有ID属性的接口可以很整洁。但是我无法在此界面中定义parentID
,因为此属性的名称因DB中的实体而异。
答案 0 :(得分:1)
首先,正如您在评论中被告知的那样,您需要使用Expression<Func<TEntity,int>> getId
。
要使用它,请不要执行此操作entities.Select(e => getID(e))
,而只需执行此操作entities.Select(getID)
。原因是Select
期望lamba表达式,getId
包含lambda表达式。 Expression<>
是必需的,因此它是EF工作所必需的表达式树,而不是编译表达式。您可以阅读this for more information。
关于接口的替代解决方案,您必须像这样实现它:
public interface IId
{
public int GetId();
}
然后,您需要在所有类中实现它,例如:
public int GetId() { return parentId; }
或
public int GetId() { return parentId; }
您还必须将接口约束添加到通用方法,如下所示:where TEntity: class ,IId
但是你会发现两个问题:
GetId
(或者至少为那些将与thid方法一起使用的实体类型)GetId
函数无法转换为表达式树,因此EF不知道如何将其转换为SQL表达式。 (我不确定,但它甚至可能引发错误)。答案 1 :(得分:1)
我认为你的功能应该是这样的:
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);
}
并像这样使用它:
update(set, e => e.ParentID, parentID, someList, e => e.ID, somefunc);