0

假设我有以下类用于从数据库映射对象:

public class OwnedThingie
{
    public long Id {get;set;}
    public long OwnerId {get;set;}
    public UserMan Owner {get;set;}
}

public class UserMan
{
    public long Id {get;set;}
    public string Name {get;set;}
    public List<OwnedThingie> Thingies {get;set;}
}

我使用以下流畅的映射:

For<OwnedThingie>()
    .TableName("DbThingies")
    .PrimaryKey(o => o.Id, true)
    .Columns
    (
        c => 
        {
            c.Column(o => o.Id);
            c.Column(o => o.OwnerId);
            c.Column(o => o.Owner).WithName("OwnerId").Reference( um => um.Id, ReferenceType.OneToOne )
        },
        true
    );

For<UserMan>()
    .TableName("DbUsers")
    .PrimaryKey(u => u.Id, true)
    .Columns
    (
        c => 
        {
            c.Column(u => u.Id);
            c.Column(u => u.Name);
            c.Many(u => u.Thingies).Reference(o => o.OwnerId)
        },
                true
    );

这将造成巨大的内存泄漏,因为它不会将所有者 <-> thingies 识别为循环关系(具体来说,它会将OneToOne关系从 Thingie 映射到 User,然后找到与 Thingie 的Many关系,再次映射 Thingie,找到用户等等......)

我们确实需要在数据模型上同时拥有列OwnerId和属性。Owner使用过去的参考是OneToOne要走的路,但不幸的是,如果你想建立适当的关系,它会像上面所说的那样吃掉你所有的记忆。

提供一个参考框架,当我说“你所有的内存”时,我的意思是具有 17 个简单表的映射配置将导致 NPOCO 支持的服务吞下 1 到 3GB 的内存。

什么已经尝试过:

  • 通过手动保持计数或参考链,有条件地阻止它在地图中包含太多嵌套层。至少到目前为止失败了,因为似乎没有办法正确检查更大的上下文。
  • 使用.Result()and.Computed()来克服对 same-field-name 的限制(OwnerId如果您的Foreign引用被命名,则不能有字段OwnerId)。失败,因为名称保存在字典中,你无法绕过它。
  • 创建包含通用对象而不是实际数据对象的不同模型以停止连接传播。需要明确的是,class SuperUserMan: UserMan简单的 s 隐藏了令人讨厌的关系object。失败的原因尚不清楚,但很可能被 NPOCO 视为动态的。内存使用率更高。
  • 只是假装 FK 属性仍然存在 - 尝试在我们的代码中使用它们,或者更确切地说是 NPOCO 的 LINQ 表达式。失败,因为它们已添加到字典中但不能以任何方式使用。

任何建议都非常受欢迎。

使用 NPOCO 最新版本、SQL Server 2019、.NET Core 目前为 3.1.latest

这也已在 NPOCO GitHub 中作为问题打开 - 但是在这里我问是否有人有不涉及以任何方式接触 NPOCO 的解决方案。

4

1 回答 1

0

我认为您可能需要根据所需的查询来调整模型,而不是尝试适应所有可能的情况。

  • 您可以从 Thingy 到 Owner 删除关系(在您的模型中),这样当您查询所有者时,您可以带回所有的东西,但不能反过来。

如果由于某种原因您确实需要检索某个事物的所有所有者,那么您可能需要第二个模型。我认为这是所有 ORM 中都存在的常见问题,您可能必须使用内联 SQL 或过程来解决该问题。

于 2021-09-10T14:45:56.207 回答