在 EF Core 中应用投影时处理对象引用的正确方法是什么?
What is the proper way of handling object reference when applying projections in EF Core?
给定以下对象的简单示例:
public class Item
{
public int Id { get; set; }
public string Description { get; set; }
public Item ChildItem { get; set; }
}
假设:
- 这是一个简单的实体,有自己的
DbSet<Item>
。
ChildItem
属性 被配置为与 'self'. 的一对零或多关系
- 关于导航属性的关系是片面的:
builder.HasOne(x => x.ChildItem)
.WithMany()
.IsRequired(false)
.OnDelete(DeleteBehavior.Restrict);
- 实体将被投影到(为了示例而简化):
public class ItemProjection
{
public int Id { get; set; }
public ItemProjection ChildItem { get; set; }
}
- 父子关系只有一层
.AsNoTrackingWithIdentityResolution()
在创建查询以检索 Item
数据时使用。
我正在尝试找出是否有 正确 方法将实体作为投影返回。
我想到的选项是:
Return 使用标准 EF Core 机制的投影,例如 select 到 ItemProjection
或匿名类型 - 这非常简单,BUT 当多个父项引用同一个子项时,投影时 - 这些子项都是单独的实例。
Return 自定义映射将保存父子对象之间的引用关系,因此父投影在指向同一个子对象的情况下实际上将指向子投影的同一个实例.
请注意,在某些情况下,返回的集合将包含包含子项的父项和单独的子项作为没有子项的父项。在这种情况下,第一个选项也是 returns 单独的实例,尽管至少在我看来,它们应该是同一个实例。
在应用程序生命周期的后期,这些投影将被修改并转换回实体。
主要问题是 - 是否有处理此类事情的首选/正确方法?
投影背后的想法是为消费者提供消费者需要的东西,而不是数据可以提供的一切。由于投影通常用于 server/service 和 consumer/client 之间的传输层,这通常涉及序列化之类的事情,在这种情况下,担心单个实例与多个实例会变成 non-concern。最终消费者几乎总是会接收多个实例,并在将数据发送回服务器时返回多个实例。
理想情况下,预测应该将数据限制在消费者需要看到的范围内,这可能意味着如果维护数据关系没有真正的好处,则需要扁平化数据关系。这也可能意味着虽然您的域模型可能被规范化为 Item Item -> Item Child,但您预计的“child”不需要公开其底层“Item”具有的所有内容,(包括它自己可能的 child) 在这种情况下你可以考虑:
ItemProjection
{
Id,
// ... Item Fields
ChildId,
ChildField
// ...
}
或
ItemProjection
{
Id,
// ... Item Fields
ChildProjection Child
}
其中 ChildProjection 是一个单独的定义,特定于表示此关系中的 child 所需的数据。 (不一定是所有“项目”字段)
大多数情况下,对于 1..1 / 0..1 关系,我选择展平投影,因为 child(ren) 中我关心的字段数量相对较少。对于我确实需要 child 的更多细节的情况,我将使用 child 投影。在我的消费者特别想要构建一个 self-referencing 树的情况下,我只会考虑类似 ItemProjection Child
的东西。
给定以下对象的简单示例:
public class Item
{
public int Id { get; set; }
public string Description { get; set; }
public Item ChildItem { get; set; }
}
假设:
- 这是一个简单的实体,有自己的
DbSet<Item>
。 ChildItem
属性 被配置为与 'self'. 的一对零或多关系
- 关于导航属性的关系是片面的:
builder.HasOne(x => x.ChildItem)
.WithMany()
.IsRequired(false)
.OnDelete(DeleteBehavior.Restrict);
- 实体将被投影到(为了示例而简化):
public class ItemProjection
{
public int Id { get; set; }
public ItemProjection ChildItem { get; set; }
}
- 父子关系只有一层
.AsNoTrackingWithIdentityResolution()
在创建查询以检索Item
数据时使用。
我正在尝试找出是否有 正确 方法将实体作为投影返回。
我想到的选项是:
Return 使用标准 EF Core 机制的投影,例如 select 到
ItemProjection
或匿名类型 - 这非常简单,BUT 当多个父项引用同一个子项时,投影时 - 这些子项都是单独的实例。Return 自定义映射将保存父子对象之间的引用关系,因此父投影在指向同一个子对象的情况下实际上将指向子投影的同一个实例.
请注意,在某些情况下,返回的集合将包含包含子项的父项和单独的子项作为没有子项的父项。在这种情况下,第一个选项也是 returns 单独的实例,尽管至少在我看来,它们应该是同一个实例。
在应用程序生命周期的后期,这些投影将被修改并转换回实体。
主要问题是 - 是否有处理此类事情的首选/正确方法?
投影背后的想法是为消费者提供消费者需要的东西,而不是数据可以提供的一切。由于投影通常用于 server/service 和 consumer/client 之间的传输层,这通常涉及序列化之类的事情,在这种情况下,担心单个实例与多个实例会变成 non-concern。最终消费者几乎总是会接收多个实例,并在将数据发送回服务器时返回多个实例。
理想情况下,预测应该将数据限制在消费者需要看到的范围内,这可能意味着如果维护数据关系没有真正的好处,则需要扁平化数据关系。这也可能意味着虽然您的域模型可能被规范化为 Item Item -> Item Child,但您预计的“child”不需要公开其底层“Item”具有的所有内容,(包括它自己可能的 child) 在这种情况下你可以考虑:
ItemProjection
{
Id,
// ... Item Fields
ChildId,
ChildField
// ...
}
或
ItemProjection
{
Id,
// ... Item Fields
ChildProjection Child
}
其中 ChildProjection 是一个单独的定义,特定于表示此关系中的 child 所需的数据。 (不一定是所有“项目”字段)
大多数情况下,对于 1..1 / 0..1 关系,我选择展平投影,因为 child(ren) 中我关心的字段数量相对较少。对于我确实需要 child 的更多细节的情况,我将使用 child 投影。在我的消费者特别想要构建一个 self-referencing 树的情况下,我只会考虑类似 ItemProjection Child
的东西。