C# 如何使用EF优化此查询
您好,我是实体框架的新手。我只是想知道是否有办法改进我的实现。这是密码C# 如何使用EF优化此查询,c#,entity-framework-core,C#,Entity Framework Core,您好,我是实体框架的新手。我只是想知道是否有办法改进我的实现。这是密码 public async Task<List<Record>> GetRecordsByBatchId(string batchId, string source) { List<string> idList = new List<string>(); //[1] Get all parent ID from table 1 wit
public async Task<List<Record>> GetRecordsByBatchId(string batchId, string source)
{
List<string> idList = new List<string>();
//[1] Get all parent ID from table 1 with a filter of source and batchId
var parentIds= await _context.Set<FirstTable>()
.Where(a => a.IsActive
&& a.BatchId.Equals(batchId)
&& a.Source.Equals(source)).Select(b => b.ParentId).ToListAsync();
if (parentIds.Count() == 0)
{
return new List<Record>();
}
//[2] Query idNumber of each parentId from [1] to SecondTable
List<long> idNumber = await _context.Set<SecondTable>()
.Where(a => parentIds.Contains(a.Id))
.Select(b => b.IdNumber).ToListAsync();
//[3] Query Record/s that contains idNumber from previous query [2]. it is possible that 1 or
//more records has same idNumber
List<Risk> recordByIdNumber = await _context.Set<SecondTable>()
.Where(a => idNumber.Contains(a.IdNumber)).ToListAsync();
//[4] In this part I just want to group the records in [3] by Id number and sort each group
//by its endorsementNumber in descending order and return the record with highest endorsement
//number for each group
return (from record in recordByIdNumber
group record by record.IdNumber into g
orderby g.Key
select g.OrderByDescending(risk =>risk.EndorsementNumber).FirstOrDefault()).ToList();
}
}
第二个表的模型
public class FirstTable
{
public Guid? ParentId{ get; set; }
public string BatchId { get; set; }
public string Source { get; set; }
public bool IsActive { get; set; }
}
public class SecondTable
{
public Guid Id{ get; set; }
public int EndorsementNumber { get; set; }
public long IdNumber { get; set; }
}
注意:我只是在模型中包含了必要的属性
这种方法正如预期的那样发挥作用。我只是想知道这些查询是否有可能被优化,因为对于SecondTable表只有一个查询
任何帮助都将不胜感激,提前感谢。var parentIds=\u context.Set()
var parentIds = _context.Set<FirstTable>()
.Where(a => a.IsActive
&& a.BatchId.Equals(batchId)
&& a.Source.Equals(source)).Select(b => new { b.parentId });
var risks = await (from s in _context.Set<SecondTable>()
join p in parentIds on s.Id equals p.parentId
join r in _context.Set<SecondTable>() on s.IdNumber equals r.IdNumber
select r).GroupBy(r=>r.IdNumber)
.Select(r=> r.OrderByDescending(risk =>risk.EndorsementNumber).FirstOrDefault())
.ToArrayAsync();
return risks;
.其中(a=>a.IsActive
&&a.BatchId.Equals(BatchId)
&&a.Source.Equals(Source)).Select(b=>new{b.parentId});
var risks=await(来自_context.Set()中的s)
在s上的parentId中加入p。Id等于p.parentId
在s.IdNumber上的_context.Set()中加入r等于r.IdNumber
选择r).GroupBy(r=>r.IdNumber)
.Select(r=>r.OrderByDescending(risk=>risk.背书编号).FirstOrDefault())
.ToArrayAsync();
退货风险;
您可以有1个查询,而不是3个查询。随着第一个查询的行数增加,它的性能会更好
编辑:正如评论中提到的@SvyatoslavDanyliv,根据EF的版本和您使用的提供者,组获取操作可能无法工作。您可能需要按如下操作分离查询和组:
var result = await (from s in _context.Set<SecondTable>()
join p in parentIds on s.Id equals p.parentId
join r in _context.Set<SecondTable>() on s.IdNumber equals r.IdNumber
select r).ToArrayAsync();
var risks = result.GroupBy(r=>r.IdNumber)
.Select(r=> r.OrderByDescending(
risk =>risk.EndorsementNumber).FirstOrDefault())
.ToArray();
return risks;
var result=await(来自_context.Set()中的s)
在s上的parentId中加入p。Id等于p.parentId
在s.IdNumber上的_context.Set()中加入r等于r.IdNumber
选择r).ToArrayAsync();
var风险=结果.GroupBy(r=>r.IdNumber)
.选择(r=>r.OrderByDescending(
risk=>risk.背书编号).FirstOrDefault()
.ToArray();
退货风险;
var parentIds=\u context.Set()
.其中(a=>a.IsActive
&&a.BatchId.Equals(BatchId)
&&a.Source.Equals(Source)).Select(b=>new{b.parentId});
var risks=await(来自_context.Set()中的s)
在s上的parentId中加入p。Id等于p.parentId
在s.IdNumber上的_context.Set()中加入r等于r.IdNumber
选择r).GroupBy(r=>r.IdNumber)
.Select(r=>r.OrderByDescending(risk=>risk.背书编号).FirstOrDefault())
.ToArrayAsync();
退货风险;
您可以有1个查询,而不是3个查询。随着第一个查询的行数增加,它的性能会更好
编辑:正如评论中提到的@SvyatoslavDanyliv,根据EF的版本和您使用的提供者,组获取操作可能无法工作。您可能需要按如下操作分离查询和组:
var result = await (from s in _context.Set<SecondTable>()
join p in parentIds on s.Id equals p.parentId
join r in _context.Set<SecondTable>() on s.IdNumber equals r.IdNumber
select r).ToArrayAsync();
var risks = result.GroupBy(r=>r.IdNumber)
.Select(r=> r.OrderByDescending(
risk =>risk.EndorsementNumber).FirstOrDefault())
.ToArray();
return risks;
var result=await(来自_context.Set()中的s)
在s上的parentId中加入p。Id等于p.parentId
在s.IdNumber上的_context.Set()中加入r等于r.IdNumber
选择r).ToArrayAsync();
var风险=结果.GroupBy(r=>r.IdNumber)
.选择(r=>r.OrderByDescending(
risk=>risk.背书编号).FirstOrDefault()
.ToArray();
退货风险;
是的,查询1-3可以并且应该合并。为此,您需要在模型中具有导航属性。第一个表和第二个表之间似乎存在一对多关系。让我们使用客户和订单代替
class Customer {
int CustomerId
string BatchId
ICollection<Order> Orders
}
class Order {
int OrderId
int CustomerId
Customer Customer
Risk Risk
}
class客户{
int客户ID
字符串批处理ID
I收款单
}
阶级秩序{
整型医嘱ID
int客户ID
顾客顾客
风险
}
在这种情况下,只需将第三个查询编写为
List<Risk> = await _context.Orders.Where(o => o.Customer.BatchId == batchId)
.Select(o => o.Risk).ToListAsync();
List=wait\u context.Orders.Where(o=>o.Customer.BatchId==BatchId)
.选择(o=>o.Risk).toListSync();
显然,我只是在猜测结构和关系。但希望这能让你开始。对我来说,
Contains()
是“代码气味”。第一次查询中很有可能会有一个很大的列表,并且contains()会在数据库中生成一个巨大的IN
子句,这很容易使系统崩溃是的,查询1-3可以而且应该组合在一起。为此,您需要在模型中具有导航属性。第一个表和第二个表之间似乎存在一对多关系。让我们使用客户和订单代替
class Customer {
int CustomerId
string BatchId
ICollection<Order> Orders
}
class Order {
int OrderId
int CustomerId
Customer Customer
Risk Risk
}
class客户{
int客户ID
字符串批处理ID
I收款单
}
阶级秩序{
整型医嘱ID
int客户ID
顾客顾客
风险
}
在这种情况下,只需将第三个查询编写为
List<Risk> = await _context.Orders.Where(o => o.Customer.BatchId == batchId)
.Select(o => o.Risk).ToListAsync();
List=wait\u context.Orders.Where(o=>o.Customer.BatchId==BatchId)
.选择(o=>o.Risk).toListSync();
显然,我只是在猜测结构和关系。但希望这能让你开始。对我来说,
Contains()
是“代码气味”。您的第一个查询很可能会有一个很大的列表,contains()会在数据库中生成一个巨大的IN
子句,这很容易使系统崩溃,我认为需要对您的模型进行描述才能理解您的代码。Hello@RoyCohen我刚刚更新了我的问题,包括模型,thanksHi@Felix我刚刚再次编辑了模型,很抱歉造成混淆,因为我刚刚从实际的属性重命名了这些属性。@Edward-不仅仅是Id(尽管命名一致性会有所帮助)。应该有导航属性来实现关系(请参见答案中的示例!)!在关系数据库中,不仅仅是列的名称,还有强制一对多关系的外键约束。EF还需要实现对象之间的关系,而不是xyz.Count()==0
y