【问题标题】:Mapping many-to-one with collection table与集合表进行多对一映射
【发布时间】:2014-05-07 12:09:05
【问题描述】:

我有两个实体MachineProduct 的简单案例,其中Machine 可以有零个或一个Product。代码中不需要反向关联(可能是某种集合)。

问题出在遗留的数据库模型中,我无法更改 Machine 表的结构,因此我创建了一个额外的表 MachineProduct,其中包含两个表的外键。基本上你会为多对多关系做什么,但实际上此表中的 MachineId 将是唯一的。

现在我需要在 NHibernate 中映射它。我能做的是将它映射为多对多集合,并确保 Machine.Products 集合中的元素不超过一个,但我觉得应该有一种更准确的方法来处理这个问题。我想这就是 ORM 映射的全部意义所在。

我正在使用 NHibernate 代码映射,但 XML 映射示例也可以。

【问题讨论】:

  • 现有机器(表)是否对产品有 FK?像 Machine.ParentProductSurrogateKey 一样? (我认为如果它存在,它将可以为空)....
  • 没有。如果是这样的话,我可以使用简单的多对一。问题是我没有权限在数据库中添加该关系。
  • 好的,我现在明白了。您正在尝试添加一个不存在但不修改原始表的关系。我没有答案,但让我看看我曾经遇到过的东西。

标签: nhibernate nhibernate-mapping nhibernate-mapping-by-code


【解决方案1】:

我认为常规的多对多应该完成工作的最简单方法,确保不要引用产品中的多对多关系。

<class name="Machine">
  <id ....>
  <bag name="Competencies" table="MachineProduct">
    <key column="machine_id"/>
   <many-to-many class="Product" column="product_id"/>
  </bag>
</class>

或常规的一对多作品。

<set name="MachineProduct" table="MachineProduct" cascade="all-delete-orphan" inverse="true">
  <key column="machine_id"/>
  <one-to-many class="MachineProduct"/>
</set>

【讨论】:

  • 第一个解决方案是我现在所拥有的,但我觉得应该有一些更好的方法,因为我实际上并不需要一个集合。但正如问题中所说,我可以添加一些代码来管理集合的使用,并将其作为常规关联公开。
  • 我不确定你需要什么...一对一关系呢?
  • 逻辑上它是多对一的。通常您可以只使用数据库中的外键来执行此操作,但由于我们不允许更改包含表 Machine 的架构,因此我正在使用连接表(与多对多关系一样)。我正在寻找的是一种 NHibernate 机制,它允许通过连接表进行多对一映射......
【解决方案2】:

这是我有根据的猜测。

正如您所建议的,在正常的 M:N 情况下,MachineProduct 将是一个“链接表”并且可以重复。

我认为您可以“单一化”这些关系...使用“.Unique()”。

我认为这是正确的树。

public class MachineProductMap : ClassMap<MachineProductNHEntity>
{
    public MachineProductMap()
    {
        Schema("dbo");
        Table("MachineProduct");

        /* Your surrogate key setup here */
        Id(x => x.MachineProductUUID).GeneratedBy.GuidComb().Index("IX_MachineProduct_MachineProductUUID");

        References<MachineNHEntity>(x => x.ParentMachine)
            .Class(typeof(MachineNHEntity))
            .Not.Nullable()
             .Unique()
            .Column("ParentMachineUUID")
            .Index("IX_MachineProduct_ParentMachineUUID")
            .Cascade.SaveUpdate()
            ;
        ;


       References<ProductNHEntity>(x => x.ParentProduct)
            .Class(typeof(ProductNHEntity))
             .Nullable()
             .Unique()
            .Column("ParentProductUUID")
            .Index("IX_MachineProduct_ParentProductUUID")
            .Cascade.SaveUpdate()
            ;
        ;
    }
}

追加:

我认为上述方法可行,但您后来声明您不想要中间人实体。

所以这是另一个使用“加入”的尝试.....

我想你想要这样的东西:

public class Product
{
    public virtual int ProductSurrogateKey { get; set; } /* ID */
}   

public partial class Machine
    {
        public virtual Guid? MachineUUID { get; set; }
        public virtual Product TheProduct { get; set; }
    }

public class MachineMap : ClassMap<Machine>
{
    public MachineMap()
    {

        Table("Machine");

        Id(x => x.MachineUUID).GeneratedBy.GuidComb().Index("IX_Machine_MachineUUID");

        Join("MachineProductArtificialReferenceMaker", join =>
        {
            join.KeyColumn("ParentMachineUUID");
            join.References(prop => prop.TheProduct);
        });

    }
}

这将创建一个名为“MachineProductArtificialReferenceMaker”的表。

此表具有 Machine.MachineUUID 的 FK。 (非空)

和 Product.ProductSurrogateKey 的 FK(可为空)

【讨论】:

  • 这不是我的想法。将连接表映射到实体似乎有点过头了,因为它不会添加任何其他值。
  • 我添加了第二个答案。它“在那里”,但我认为它有效。
  • 谢谢,但这只是部分工作。它将正确创建和更新 MachineProduct 记录,但当我将 Machine.Product 设置为 null 时,它不会删除该记录。 NHibernate Join 概念显然不是为了应付我的用例而设计的。
  • 这就是我得到的一切,伙计。祝你好运。考虑到这些选项,如果是我,我只会在新表中保留一个良性的行。
猜你喜欢
  • 2017-02-14
  • 1970-01-01
  • 2021-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-05
相关资源
最近更新 更多