.net 使用Fluent NHibernate映射许多实体使用的本地化实体集合

.net 使用Fluent NHibernate映射许多实体使用的本地化实体集合,.net,nhibernate,orm,fluent-nhibernate,mapping,.net,Nhibernate,Orm,Fluent Nhibernate,Mapping,我正在使用一个遗留数据库,并试图用Fluent NHibernate映射某种本地化表 该表如下所示: DataName [PK] TableName [PK] FieldName [PK] Id [PK] LangId Description public class Carrier { public virtual int CarrId { get; set; } public virtual string CarrCode { get; set; } public

我正在使用一个遗留数据库,并试图用Fluent NHibernate映射某种本地化表

该表如下所示:

DataName
[PK] TableName
[PK] FieldName
[PK] Id
[PK] LangId
Description
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(); ... } } 此表通过此实体映射:

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:EntityBase { 公共虚拟字符串TableName{get;set;} 公共虚拟字符串字段名{get;set;} 公共虚拟整数Id{get;set;} 公共虚拟语言{get;set;} 公共虚拟字符串描述{get;set;} ... } 公共类DataNameMap:ClassMap { 公共DataNameMap() { 表(“zDataName”); CompositeId().KeyProperty(x=>x.TableName) .KeyProperty(x=>x.FieldName) .KeyProperty(x=>x.Id) .KeyProperty(x=>x.Language,“LangId”).CustomType(); 映射(x=>x.Description)。列(“Descr”)。长度(2000); } } 为了本地化,我将多个实体映射到“DataName”实体,映射如下所示:

DataName
[PK] TableName
[PK] FieldName
[PK] Id
[PK] LangId
Description
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(); ... } } 公营航空公司 { 公共虚拟整数CarrId{get;set;} 公共虚拟字符串代码{get;set;} 公共虚拟列表DataNameList{get;set;} ... } 公共类承载器映射:类映射 { 公共运输工具地图() { 表(“承运人”); Id(x=>x.CarrId).GeneratedBy.Identity(); Map(x=>x.CarrCode).Not.Nullable().Length(8); HasMany(x=>x.DataNameList) .KeyColumn(“Id”) .Where(“表名='carriers'和字段名='name'”) .Inverse() .Cascade.AllDeleteOrphan(); ... } } “DataName”表包含的记录如下所示:

TableName FieldName Id LangId Description --------- --------- -- ------ ----------- Carriers Name 1000 1 English description Carriers Name 1000 2 French description TableName字段名Id LangId说明 --------- --------- -- ------ ----------- 承运人名称1000 1英文描述 承运人名称1000 2法语描述 我可以毫无问题地从数据库中检索这些信息,但是当需要将新实体(插入或更新)保存到数据库时,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.... 将值('Carriers','Name',1,NULL,'English Description')插入到数据名(TableName,FieldName,LangId,Id,Description)中 将值('Carriers','Name',2,NULL,'French Description')插入到数据名(TableName,FieldName,LangId,Id,Description)中 插入载体。。。。 在本例中,假设数据库生成的id为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 更新DataName集合Id=2000 其中TableName='Carriers'和FieldName='Name',LangId=1,Id为NULL 更新DataName集合Id=2000 其中TableName='Carriers'和FieldName='Name',LangId=2,Id为NULL 我尝试过为DataNameList集合使用HasMany映射的Inverse()选项,但它似乎对这种特殊情况没有任何影响

我如何告诉NHibernate保留“Carrier”实体,然后保留“DataName”集合,而不必在插入“Carrier”实体后发出额外的UPDATE语句?

在这种情况下(可能与旧数据库相关),NHibernate工作正常,正如预期的那样。我会尽力解释原因。我们必须遵守齐平顺序和一列的双重使用:

首先,会话刷新的顺序。 NHibernate文件sais:

9.6冲洗()

SQL语句按以下顺序发出

  • 所有实体插入,使用ISession.Save()以相同的顺序保存相应的对象
  • 所有实体更新
  • 所有集合删除
  • 所有集合元素的删除、更新和插入
  • 所有集合插入
  • 所有实体删除,按照使用ISession.Delete()删除相应对象的相同顺序
第二,双列映射。 上面显示的代码段使用一列:
Id
(在表DataName中)用于两个目的: I.作为主键(这将在INSERT语句中处理)

II.作为两个实体载体的参考

HasMany(x => x.DataNameList)
.KeyColumn("Id")
...
最后:会发生什么 因此,答案是:NHibernate必须在第一轮中插入所有实体。如果将有一些多对一映射,那么也可以将其作为INSERT的一部分来完成。因此,将插入
DataName
s以及
Carrier

但在我们的示例中,我们还需要持久化集合(DataNameList)。因此,现在NHibernate更新了所有(刚刚插入的)收集项目,以提供给所有者(
Carrier

暗示 所以这就是为什么我会将观察到的行为标记为“预期行为”。为了避免更新,我们可以将列表映射设置为
cascade=“none”
,并手动管理持久性(例如Call Session.Save(Carrier),然后将Carrier分配给每个DataName和Call Session.Save(DataName)

编辑:扩展建议 I.生成插入和更新的设置

通过这种设置,我可以重复你经历过的行为 C#类载波映射到DataName

private IList<DataName> _dataNames;
public virtual IList<DataName> DataNames
{
  get { return _dataNames ?? (_dataNames = new List<DataName>()); }
  set { _dataNames = value; }
}
这将导致插入和更新

II.工作设置,只需插入即可

如果我做了以下更改: 1) 将反向更改为true
reverse=“true”
2) 根据其持有者(承运人)显式设置DataName.Id

然后只应用INSERTS语句。这有帮助吗

注意:如果该ID不会在SQL Server(identity)上生成,而是由NHibernate(HiLo)协助生成,则可以减少往返时间。

在这种情况下(可能与旧数据库相关),NHibernate工作正常,正如预期的那样。我会尽力解释原因。我们必须遵守F
// create 2 DataNames
DataName dn1 = CreateNew(LangId = 1, "English");
DataName dn2 = CreateNew(LangId = 2, "French");

// insert them into collection
carrier.DataNames.Add(dn1);
carrier.DataNames.Add(dn2);

// persist them all
session.Save(carrier);
// carrier ID must be get from the server, because of identity
session.Save(carrier);

// explicity setting of the ID
dn1.Id = carrier.ID;
dn2.Id = carrier.ID;

// inverse set to false 
carrier.DataNames.Add(dn1);
carrier.DataNames.Add(dn2);

// Update via the carrier entity, will trigger INSERT
session.Update(carrier);