我正在使用遗留数据库,我正在尝试使用Fluent NHibernate映射某种本地化表 .
该表如下所示:
DataName
[PK] TableName
[PK] FieldName
[PK] Id
[PK] LangId
Description
此表通过此实体映射:
public class DataName : EntityBase
{
public virtual string TableName { get; set; }
public virtual string FieldName { get; set; }
public virtual int Id { get; set; }
public virtual Language Language { get; set; }
public virtual string Description { get; set; }
...
}
public class DataNameMap : ClassMap
{
public DataNameMap()
{
Table("zDataName");
CompositeId().KeyProperty(x => x.TableName)
.KeyProperty(x => x.FieldName)
.KeyProperty(x => x.Id)
.KeyProperty(x => x.Language, "LangId").CustomType();
Map(x => x.Description).Column("Descr").Length(2000);
}
}
为了本地化,我有多个实体映射到“DataName”实体,映射如下所示:
public class Carrier
{
public virtual int CarrId { get; set; }
public virtual string CarrCode { get; set; }
public virtual List DataNameList { get; set; }
...
}
public class CarrierMap : ClassMap
{
public CarrierMap()
{
Table("Carriers");
Id(x => x.CarrId).GeneratedBy.Identity();
Map(x => x.CarrCode).Not.Nullable().Length(8);
HasMany(x => x.DataNameList)
.KeyColumn("Id")
.Where("TableName = 'carriers' AND FieldName = 'name'")
.Inverse()
.Cascade.AllDeleteOrphan();
...
}
}
“DataName”表包含如下所示的记录:
TableName FieldName Id LangId Description
--------- --------- -- ------ -----------
Carriers Name 1000 1 English description
Carriers Name 1000 2 French description
我可以毫无问题地从数据库中检索此信息,但是当需要将新实体(插入或更新)保存到数据库时,NHibernate不会按正确的顺序执行操作 .
INSERT INTO DataName (TableName, FieldName, LangId, Id, Description) VALUES ('Carriers', 'Name', 1, NULL, 'English description')
INSERT INTO DataName (TableName, FieldName, LangId, Id, Description) VALUES ('Carriers', 'Name', 2, NULL, 'French description')
INSERT INTO Carriers....
For the purpose of this example, let's say the id generated by the database is 2000.
UPDATE DataName SET Id = 2000
WHERE TableName = 'Carriers' AND FieldName = 'Name' AND LangId = 1 AND Id IS NULL
UPDATE DataName SET Id = 2000
WHERE TableName = 'Carriers' AND FieldName = 'Name' AND LangId = 2 AND Id IS NULL
我尝试使用我的HasMany映射的Inverse()选项为DataNameList集合,但它似乎没有对这种特殊情况有任何影响 .
在插入“Carrier”实体后,如何告诉NHibernate持久保存“Carrier”实体然后收集“DataName”而不必发出额外的UPDATE语句?
1 回答
在这种情况下(可能与遗留数据库相关)NHibernate正如预期的那样正常工作 . 我会尝试解释原因 . 我们必须观察FLUSH Ordering和一列的双重用法:
首先,会话刷新的顺序 .
NHibernate文档sais:
其次,双列映射 .
上面显示的代码段使用一列: Id (在表DataName中)有两个用途: I. 作为主键(这将在INSERT语句中处理)
II. 作为参考两个实体的承运人
最后:会发生什么
鉴于此,答案是:NHibernate必须在第一轮中插入所有实体 . 如果有一些多对一的映射,它也可以作为INSERT的一部分完成 . 所以插入
DataName
和Carrier
.但在我们的例子中,我们还需要持久化Collection(
DataNameList
) . 所以现在NHibernate更新所有(刚插入的)集合项目,以提供所有者(Carrier
)建议
所以这就是我将这种观察到的行为标记为"the expected one"的原因 . 为了避免UPDATE,我们可以将列表映射设置为
cascade="none"
并手动管理持久性(例如,调用Session.Save(Carrier),然后将Carrier分配给每个DataName并调用Session.Save(DataName),...
编辑:扩展建议
I. settings producing INSERT and UPDATE
通过这些设置,我能够重复您经历过C#类载波映射到DataName的行为
XML映射(与您的流利相同,但与 false 相反)
导致相同问题的代码,您已在上面描述过:
这导致INSERTS更新
II. working settings, just with INSERT
如果我进行了这些更改:1)将逆转换为 true
inverse="true"
2)根据其持有者(运营商)明确设置DataName.Id然后只应用INSERTS语句 . 这有用吗?
注意:如果不在SQL Server(身份)上生成ID,但由NHibernate(HiLo)协助,则可以减少往返 .