示例模型。
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; }
}
约束。
子级具有 RootId 和 Code 属性作为其唯一键。这意味着,只要没有两个或更多的Child包含相同的代码,每个Root对象将只允许具有多个Child对象。
示例查询
获取代码为A100的所有带有Child的根记录。
包含两个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记录及其所有子级。然后,迭代每个记录,并删除所有与我要查询的代码不同的子级。这种方法的问题在于,当数据库增长时,它将对这种方法产生影响,因为当我需要的每个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();
在我的情况下,使用构造函数也不理想,因为我在实例化过程中将每个对象的状态设置为已创建,这是每个模型设计的一部分。
编辑1
我可以使用Select()在LINQ投影中使用构造函数,但是我的问题是,在我的所有模型中,都有一个名为 State 的属性,根据该属性,我可以在模型的各个点进行更新关于发生了什么。在构造器部分,我将其更新为 Create 状态,以暗示已创建新模型。因此,如果我要创建一个构造函数,以便可以从数据库中创建模型的实例,那会引起混乱,因为我只是从数据库中检索一个已经存在的记录,并且如果要使用构造函数,代码,在实例化期间会将模型标记为 Created (创建),这不是我想要的,因为它将在设计中创建新的含义。
编辑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();
最重要的是,是否可以使用查询或其他任何方法直接从数据库获取想要的记录,而无需执行查询的第二部分?
答案 0 :(得分:1)
除非可以在数据存储中进行某种排序,否则仍然需要“检索”项目才能对其进行查看。而且,如果您希望将数据与结果进行复制而不是修改您的 context 数据,则需要某种克隆。因此,我认为-考虑到您的限制-最好仅保留对生成的Root
和Child
项目的引用:
var l = new List<Tuple<Root, Child>>();
foreach(var p in context.Roots.Include(x => x.Children))
{
foreach(var c in p.Children)
{
if(c.Code == "A100")
{
l.Add(Tuple.Create(p, c));
break;
}
}
}
这样,您只需查看子项和根项一次,并且仅检查子项,直到找到您的项。元组的结果列表包含对您各自的Root
和Child
项目的引用,而无需对其进行修改,因此请不要使用所引用的Children
项目的Root
属性。>
答案 1 :(得分:1)
尝试使用传统的LINQ,这样您就不再需要手动删除子级并将查询结果投影到匿名对象上。
__init__