【发布时间】:2019-05-20 06:59:13
【问题描述】:
示例模型。
public class Root
{
public string Id { get; private set; }
public ICollection<Child> Children { get; private set; }
}
public class Child
{
public string Id { get; private set; }
public string RootId { get; private set; }
public string Code { get; private set; }
public string Name { get; private set; }
}
约束。
Child 具有 RootId 和 Code 属性作为其唯一键。这意味着每个 Root 对象只允许有尽可能多的 Child 对象,只要没有两个或更多 Child 包含相同的代码。
示例查询
获取所有具有 Child 且 Code 等于 A100 的 Root 记录。
包含两个根对象的示例列表数据
Root1 with 2 children, one having a code A100 and the other A200.
Root2 with 2 children, one having a code A100 and the other A500.
我现在正在做的当前查询是首先获取所有根记录及其所有子记录。然后,迭代每条记录并删除其所有与我查询的代码不同的子项。这种方法的问题是当数据库增长时,它会对这种方法产生影响,因为当我只需要每个 Root 对象一个时,我会检索所有子对象。
示例代码
var records = context.Roots
.Include(x => x.Children)
.Where(x => x.Children.Any(y => y.Code == "A100"))
.ToList();
foreach (var root in records)
{
foreach (var child in root.Children)
{
if (!child.Code == "A100")
{
root.Children.Remove(child);
}
}
}
我的模型按照 DDD 原则将其属性设置器设置为私有。所以我不能使用 Select() 命令进行 linq 投影,如下所示。
var records = context.Roots
.Include(x => x.Children)
.Where(x => x.Children.Any(y => y.Code == "A100"))
.Select(x => new Root{...})
.ToList();
在我的情况下使用构造函数也不理想,因为作为每个模型设计的一部分,我在实例化期间将每个对象的状态设置为 Created。
编辑 1
我可以使用 Select() 在 LINQ 投影中使用构造函数,但我的问题是,在我的所有模型中,都有一个名为 State 的属性,我在模型中的各个点进行更新,具体取决于关于发生的事情。在构造函数部分,我将其更新为 Create 状态,以暗示新模型已创建。因此,如果我要创建一个构造函数,以便从数据库中创建模型的实例,那会导致混乱,因为我只是从数据库中检索一个已经存在的记录,并且如果我要使用构造函数,代码在实例化过程中会将模型标记为已创建,这不是我想要的,因为它会在我的设计中创造新的意义。
编辑 2
我很抱歉没有让自己足够清楚。我的问题在于查询的这一部分。
第 1 部分。
var records = context.Roots
.Include(x => x.Children)
.Where(x => x.Children.Any(y => y.Code == "A100"))
.ToList();
所以我不需要到达这部分。
第 2 部分
foreach (var root in records)
{
foreach (var child in root.Children)
{
if (!child.Code == "A100")
{
root.Children.Remove(child);
}
}
}
现在基于我提到的约束。
约束 1. 不使用公共设置器,所以我不能使用它。
var records = context.Roots
.Include(x => x.Children)
.Where(x => x.Children.Any(y => y.Code == "A100"))
.Select(x => new Root{...})
.ToList();
约束 2. 不使用构造函数
var records = context.Roots
.Include(x => x.Children)
.Where(x => x.Children.Any(y => y.Code == "A100"))
.Select(x => new Root(...))
.ToList();
最重要的是,是否有我可以使用的查询或任何其他方法直接从数据库中获取我想要的记录,而无需执行查询的第二部分?
【问题讨论】:
-
澄清一下:您正在使用示例代码删除所有非 A100 节点从原始列表数据。如果这不是您的意图,而您实际上想要一个副本,那么您需要一种方法来构造或复制至少您的根项目,这会使解决方案变得更加容易。
-
是的,我正在从从数据库检索到的列表中删除所有非 A100 节点,因为使用此命令获取所有子记录 Where(x => x.Children.Any(y => y.代码 == “A100”))。我试图弄清楚如何只获取一个子记录,而不是根据我上面提到的约束来检索所有子记录。
-
如果在
select子句中将查询结果展平为匿名对象会怎样? -
您对实体模型施加了太多约束,这应该是logical data model。一般来说,将domain model 与 LDM 混合不是一个好主意 - LDM 不能具有所有这些约束(私有设置器、get/set 行为、构造函数逻辑等)。更好地创建单独的模型并在需要时在两者之间进行映射。无论如何,您使用的是什么 EF(EF6、EF Core(版本?))?根据这一点,这个特定问题可能会有解决方案。
-
@devpro101,我在下面添加了我的答案,试试看,让我知道:)
标签: c# entity-framework linq domain-driven-design