Entity Framework 核心读取和更新多行 - 复合主键
Entity Framework Core Read & Update Multiple rows - Composite Primary Key
我有这样的 table 结构:
ID Code Value
1 2 text1
2 3 text3
2 4 text4
此处 ID 和代码构成复合主键,即在上面 table 你不能有 ID = 2 和代码 = 4 的另一行。
现在我们正在使用 entity framework 核心,我有一个名为 Branch 的 class(代表复合键),它看起来像这样:
public class Branch
{
public int ID {get; set;}
public int Code {get; set;}
}
其次我也有一个List<Branch>
。现在我想做两件事:
首先进行一次数据库调用并获取整个 Branch 列表的完整对象(ID、代码、值)。
之后,我将为每个对象更改'Value'。
然后我想进行一次数据库调用并为每一行保存更新后的 'Value'。
目前我正在循环执行此操作,因此效率很低。
foreach(var x in listOfBranch)
{
var record = context.Table.Find(x.ID, x.Code);
record.Value = "new value";
context.SaveChanges();
}
我们如何在一个电话中做到这一点?谢谢。
Now I want to do two things:
First make one database call and get the full object (ID, Code, Value) for the entire list of Branch.
After that, I will change the 'Value' for each object.
Then I want to make one database call and save the updated 'Value' for each row.
第二部分很简单 - 只需将 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
class 方法构建上述谓词,如下所示(只需将 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();
我有这样的 table 结构:
ID Code Value
1 2 text1
2 3 text3
2 4 text4
此处 ID 和代码构成复合主键,即在上面 table 你不能有 ID = 2 和代码 = 4 的另一行。
现在我们正在使用 entity framework 核心,我有一个名为 Branch 的 class(代表复合键),它看起来像这样:
public class Branch
{
public int ID {get; set;}
public int Code {get; set;}
}
其次我也有一个List<Branch>
。现在我想做两件事:
首先进行一次数据库调用并获取整个 Branch 列表的完整对象(ID、代码、值)。
之后,我将为每个对象更改'Value'。
然后我想进行一次数据库调用并为每一行保存更新后的 'Value'。
目前我正在循环执行此操作,因此效率很低。
foreach(var x in listOfBranch)
{
var record = context.Table.Find(x.ID, x.Code);
record.Value = "new value";
context.SaveChanges();
}
我们如何在一个电话中做到这一点?谢谢。
Now I want to do two things:
First make one database call and get the full object (ID, Code, Value) for the entire list of Branch.
After that, I will change the 'Value' for each object.
Then I want to make one database call and save the updated 'Value' for each row.
第二部分很简单 - 只需将 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
class 方法构建上述谓词,如下所示(只需将 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();