使用未映射的列映射复合键

Posted

技术标签:

【中文标题】使用未映射的列映射复合键【英文标题】:Map composite key with unmapped column 【发布时间】:2011-12-13 16:32:04 【问题描述】:

如果复合键的一部分未映射到我的实体中,我该如何映射它?

例子:

我有一个表 ITEMDELIVERY 包含列:

ITEMDELIVERY_ID (PK) DELIVERY_DATE(PK)

我有一个表 ITEMDELIVERYDETAIL 包含列:

ITEMDELIVERYDETAIL_ID (PK) ITEMDELIVERY_ID (FK) PARTITIONDATE(PK、FK)

如您所见,两个表中都有一个复合键,ITEMDELIVERYDETAIL 有一个指向ITEMDELIVERY 的“复合”外键。

在我的域模型ItemDeliveryDetail 中不存在可以映射到列PARTITIONDATE 的属性PartitionDate(请参阅here 和here 了解原因)。

但是现在,我如何映射ITEMDELIVERYDETAIL 中的复合键?

我尝试了以下方法,但不起作用:

mapping.CompositeId().KeyProperty(x => x.Id, "ITEMDELIVERYDETAIL_ID")
                     .KeyProperty(x => x.ItemDelivery.DeliveryDate,
                                       "PARTITIONDATE");

我收到以下错误:

NHibernate.PropertyNotFoundException:在“REM.Domain.NHibernate.ItemDeliveryDetail”类中找不到属性“DeliveryDate”的getter


更新:

我想我找到了解决办法:

    ItemDeliveryDetail的映射中删除对ItemDelivery的引用:mapping.References(x => x.ItemDelivery);.Columns("ITEMDELIVERY_ID", "PARTITIONDATE");

    将复合键的声明改为:

    mapping.CompositeId().KeyProperty(x => x.Id, "ITEMDELIVERYDETAIL_ID")
                         .KeyReference(x => x.ItemDelivery, "ITEMDELIVERY_ID",
                                                            "PARTITIONDATE");
    

这具有保存ItemDeliveryDetail 不能级联保存ItemDelivery 的副作用。需要提前保存。

但是,我想知道一件事:这会创建一个包含三列的 PK 吗?如果是这样,如何避免它并且只为需要的两列创建一个PK?

【问题讨论】:

【参考方案1】:

看起来您有一个遗留数据库,并且永远不会使用 SchemaExport 生成它,因此 NH 认为它有 3 个或 1 个 PK 列并不重要。

在查看您的问题Composite key with sequence 之后,如果您的 ID 是唯一的,那么最好

mapping.Id(x => x.Id).GeneratedBy.SequenceIdentity("SQ_TRANSFORM_ITEMDEL_IDDID");
mapping.Reference(x => x.ItemDelivery).Columns("ITEMDELIVERY_ID", "PARTITIONDATE");

即使在数据库中,PK 跨越两列

更新:您的发票示例中的棘手问题。在联接中有第二列(作为查询优化器应添加到联接的位置)有一个技巧

HasManyToMany(u => u.ItemDeliveryDetails)
    .Table("INVOICEITEM_IDD")
    .ChildWhere("PARTITIONDATE = nhGeneratedAliasForINVOICEITEM_IDD.PARTITIONDATE");

【讨论】:

您对遗留数据库的假设是正确的。但是,将用于持久性规范测试的测试数据库应该通过模式导出来创建,以确保干净可靠的测试环境。 我有相同的场景,一个遗留数据库和映射的单元测试。但是我不使用 SchemaExport,因为它可能会掩盖映射错误。我将生产数据库的架构导出到一个 sqlscript 中,我在创建 sessionfactory 后立即执行。 好点。不过,我需要正确映射还有另一个原因:有些表有一个指向ITEMDELIVERYDETAIL 的外键。为确保生成的连接尽可能快,此外键还需要使用两列。如果我使用您的答案,这将不起作用,因为 ITEMDELIVERYDETAIL 仅使用一个 ID 进行映射... 如果只加入索引 (pk) 的一列,您确定在 oracle 中性能会下降那么多吗?我想不出一种方法来模拟映射中的 db 模式而不会遇到很多麻烦 是的。这就是我们在创建该数据库时引入该列和分区的全部目的。这是一个相当大的表,有 3000 万个条目……只是一些数字:单行没有分区日期的连接需要 11 秒。与分区日期的连接是即时的。

以上是关于使用未映射的列映射复合键的主要内容,如果未能解决你的问题,请参考以下文章

具有复合键的一对多注释映射

如何进行 Hibernate XML 映射,一对多使用 1 PK 映射到另一个具有复合键的实体

Fluent NHibernate 多对多映射,使用自动生成的 pk 而不是复合键

EF6 中使用复合键的每个具体类型 (TPC) 映射表

Hibernate 表映射 主键生成策略与复合主键

FluentNHibernate 异常:复合用户类型上的“属性映射的列数错误”