实体框架核心阅读&更新多行 - 复合主键

时间:2018-05-09 21:02:16

标签: c# entity-framework entity-framework-core dbcontext composite-key

我有一个像这样的表结构:

type Empty = (() :: Constraint)
type ConstEmpty x = (() :: Constraint)

此处ID和Code构成复合主键,即在上表中,您不能拥有ID = 2且Code = 4的另一行。

现在我们正在使用实体框架核心,我有一个名为Branch的类(代表复合键),它看起来像这样:

ID Code  Value
1  2     text1
2  3     text3
2  4     text4

其次我也有public class Branch { public int ID {get; set;} public int Code {get; set;} } 。现在我想做两件事:

首先进行一次数据库调用并获取整个Branch列表的完整对象(ID,Code,Value)。

在那之后,我将改变“价值”'对于每个对象。

然后我想进行一次数据库调用并保存更新的' Value'对于每一行。

目前我在循环中这样做是因为它效率低下。

List<Branch>

我们如何在一次通话中完成此操作?感谢。

1 个答案:

答案 0 :(得分:3)

  

现在我想做两件事:

     

首先进行一次数据库调用并获取整个Branch列表的完整对象(ID,Code,Value)。

     

在那之后,我将改变“价值”&#39;对于每个对象。

     

然后我想进行一次数据库调用并保存更新的&#39; Value&#39;对于每一行。

第二部分很简单 - 只需在循环外移动SaveChanges()

第一部分很棘手。在撰写本文时(EF Core 2.0.2),Contains只能用于单个属性,并且可以连接到内存集合,基于Concat的查询或像

这样的过滤器
.Where(e => listOfBranch.Any(b => b.ID == e.ID && b.Code == e.Code))

所有这些都没有转换为SQL并在本地进行评估。

使用单个数据库查询获得所需结果的唯一方法是动态构建如下过滤条件:

.Where(e =>
    (e.ID == listOfBranch[0].ID && e.Code == listOfBranch[0].Code)
    ||
    (e.ID == listOfBranch[1].ID && e.Code == listOfBranch[1].Code)
    // ...
    ||
    (e.ID == listOfBranch[N-1].ID && e.Code == listOfBranch[N-1].Code)
)

您可以使用Expression类方法构建上述谓词,如下所示(只需将Record替换为实体类型):

var parameter = Expression.Parameter(typeof(Record));

var body = listOfBranch
    .Select(b => Expression.AndAlso(
        Expression.Equal(Expression.Property(parameter, "ID"), Expression.Constant(b.ID)),
        Expression.Equal(Expression.Property(parameter, "Code"), Expression.Constant(b.Code))))
    .Aggregate(Expression.OrElse);

var predicate = Expression.Lambda<Func<Record, bool>>(body, parameter);

和用法:

foreach (var record in context.Table.Where(predicate))
{
    record.Value = "new value";
}
context.SaveChanges();