Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C#中基于ID在嵌套列表中填充数据?_C#_Entity Framework_Linq_Entity Framework Core - Fatal编程技术网

如何在C#中基于ID在嵌套列表中填充数据?

如何在C#中基于ID在嵌套列表中填充数据?,c#,entity-framework,linq,entity-framework-core,C#,Entity Framework,Linq,Entity Framework Core,一切都会很好,但我想知道我是否可以用更优雅的方式来做,可能是使用linqjoin或其他什么,或者我的解决方案完全正确 使用字典编辑解决方案 foreach (var car in cars) { foreach (var policy in car.PolicySummaries) { var policyDataToUse = policyData.Single(t => t.PolicyId == policy.PolicyId); p

一切都会很好,但我想知道我是否可以用更优雅的方式来做,可能是使用
linqjoin
或其他什么,或者我的解决方案完全正确


使用字典编辑解决方案

foreach (var car in cars)
{
    foreach (var policy in car.PolicySummaries)
    {
        var policyDataToUse = policyData.Single(t => t.PolicyId == policy.PolicyId);
        policy.Amount = policyDataToUse.Amount;
        policy.PolicyName = policyDataToUse.PolicyName;
    }
}

那么首先,为什么数据没有填写?在使用
从数据库实际提取
车辆期间,您应该能够填写任何相关实体中的数据。包括

var policyIds = cars.SelectMany(t => t.PolicySummaries).Select(r => r.PolicyId);
var policyDict = _context.PolicySummary.Where(t => policyIds.Contains(t.PolicyId)).ToDictionary(t => t.PolicyId);

foreach (var car in cars)
{
    foreach (var policy in car.PolicySummaries)
    {
        var policyDataToUse = policyDict[policy.PolicyId];
        policy.Amount = policyDataToUse.Amount;
        policy.PolicyName = policyDataToUse.PolicyName;
    }
}
其次,您的代码存在严重的性能问题:
policyData
是一个
IQueryable
。每次执行
policyData.Single
,都会向数据库发送一个新的查询,查看所有策略,筛选在
policyIds
中具有
id
的策略,并选择适当的一个。如果有很多策略,这将是非常低效的-每个
foreach
迭代都是一个新的查询!您应该做的可能是:

var carEntity = _context.Cars.Where(predicate).Include(c => c.PolicySummaries).Single();
获取所有相关策略。如果有很多共享策略,并且您最终在某个时候加载了其中的大部分,那么这也可能是低效的,因此,如果数据库中没有10亿个策略,那么:

var policyData = _context.PolicySummary.Where(t => policyIds.Contains(t.PolicyId)).ToList();

可以做得更好。在这一点上,这是一个时间/内存权衡,但请注意,上述任何一项都比当前的查询重载<;code>foreach
要好。

因为您已经存在到对象(而不是实体)的数据,您将无法有效地使用EntityFramework的
连接。
您需要加载丢失的数据,然后用它更新现有的汽车对象

我认为更简单的方法是用从数据库检索的对象替换策略列表

var policies = _context.PolicySummary.ToList();
使用
字典
将使更新代码更简单,并减少要执行的操作量,减少循环


注意:上述方法假设数据库中存在所有策略Id。如果没有,这些将从相应的
car.Policies
属性中删除。您可以删除
Where(allPolicies.ContainsKey)
行,如果缺少某些策略,将引发异常。

您使用的是EF吗?或者如何将对象映射到实体?如果您正在使用任何框架或ORM,那么应该有一种“正确”的方法来获取您的属性。请编辑您的问题,并向我们提供有关项目如何设置的详细信息。@nilsK实际上在这个问题中有一个标记“实体框架”。@Fabjan是的,我在他的评论后添加:)这是因为
PolicySummaryDTO
中还有一个列表。并且该
policysumarydto
中的
PolicyId
是根据该列表中的第一条记录填写的。这是个复杂的案子,我知道。我也不想让这个问题复杂化。您仍然应该能够在db fetch中实现这一点,但如果您希望单独实现,那么至少要坚持我的第二点。从效率的角度来说应该没问题。使用
Single
SingleOrDefault
取决于您想要实现什么。如果您在代码中确定数据库中应该有一条具有给定
Id
的记录,则使用
Single
。对于不存在的实体,我通常更喜欢我的存储库抛出异常,而不是返回
null
s,但这取决于具体情况。总之,说“不要使用”不是一个好建议。两者都有适当的用例。总是尽早崩溃。更好的方法是抛出一个异常并处理它——记录一个错误,告诉用户出了什么问题,然后继续。如果这不应该发生,那就是个例外。如果默认值是合理的、可用的值,则返回它。“Smth不正确”总是推断出一种应尽快提出的异常情况。@Lewis86-当错误是业务逻辑的异常时抛出异常。当数据库中必须只存在一个具有特定id的记录时,
Single
将是更容易理解的方法。通常,您在应用程序的顶层(UI或Web API)捕获所有错误,记录它们,并为用户显示/返回友好的错误消息。记录的异常提供有关错误原因的足够信息。作为奖励,应用程序的其余部分不需要处理“默认”值,这将简化代码库。当可以将它们展平并更新每个元素中的几个字段时,将新集合分配给
car.Policies
,就没有意义了
call将返回一个新的集合,该集合可能是理想的行为,也可能不是理想的行为here@Fabjan,正如您所说,这可能是一种可取的行为,也可能不是一种可取的行为;)。作为一个好处,如果要向PolicySummaryDTO类添加/删除新属性,则无需更改更新代码。Part with dictionary返回我
System.ArgumentException:'已添加具有相同键的项。关键字:0'
@DiPix,在创建字典之前,您可以根据
PolicyId
对项目进行分组,检查更新的答案。Downvoter,请留下评论,将很乐意修复或删除我的答案。
var policies = _context.PolicySummary.ToList();
var allPolicies = _context.PolicySummary
                          .Where(policy => policyIds.Contains(policy.PolicyId))
                          .Select(group => new PolicySummaryDTO
                          {
                              PolicyId = group.Key,
                              PolicyName = group.First().PolicyName,
                              Amount = group.First().Amount                  
                          })
                          .ToDictionary(policy => policy.PolicyId);

foreach (var car in cars)
{
    car.Policies = car.Policies.Select(p => p.PolicyId)
                               .Where(allPolicies.ContainsKey)
                               .Select(policyId => allPolicies[policyId])
                               .ToList();
}