运行 设置 NHibernate Envers 的问题 table 每个 class 映射

Running into problem setting NHibernate Envers with table per class mapping

我们一直在考虑使用 Envers,但 运行 遇到了障碍。我们使用 table/class 结构,每个 class 继承使用 table 几个 classes。在加载 NHibernate 和 Envers 时,当它尝试为子 classes 创建 tables 时会发生错误。

NHibernate.MappingException: Unable to build the insert statement for class Demo.Vehicle_AUD: a failure occured when adding the discriminator ---> System.ArgumentException: The column 'VehicleTypeId' has already been added in this SQL builder

Parameter name: columnName

这是一个类似于我们正在使用的示例。

// Maps to Vehicle table
public Vehicle
{
  public int VehicleId {get;set;}
  pubic VehicleType VehicleTypeId {get;set;}
}

// Maps to Vehicle table with discriminator for VehicleTypeId == Car
public Car : Vehicle
{
   public decimal MaxSpeed {get;set;}

}

// Maps to Vehicle table with discriminator for VehicleType == Airplane
public Airplane : Vehicle
{
   public decimal MaxAirspeed {get;set;}
   public decimal MaxAltitude {get;set;}
}

Table定义:

VehicleId int identity primary key
VehicleTypeId int foreign key to VehicleTypeId on VehicleType table
MaxSpeed decimal null
MaxAirspeed decimal null
MaxAltitude decimal null

我们正在使用 FluentNHibernate:

var fluentConfig = FetchDbConfiguration(connectionString)
    .Mappings(mapper =>
        {
            mapper.FluentMappings.AddFromAssemblyOf<Vehicle>()
        })
    .ExposeConfiguration(cfg =>
        {
            var enversConf = new FluentConfiguration();
            //enversConf.Audit<Vehicle>();
            enversConf.Audit<Car>();
            enversConf.Audit<Airplane>();
            nhConf.IntegrateWithEnvers(enversConf);        
        });

var nhConfiguration = fluentConfig.BuildConfiguration();
return nhConfiguration;

映射:

    public partial class VehicleMap : ClassMap<Vehicle>
    {
        public VehicleMap()
        {
        Table("Vehicle");
        LazyLoad();
        Id(x => x.VehicleId)
                    .Column("VehicleId")
                    .CustomType("Int32")
                    .Access.Property()
                    .Not.Nullable()
                    .Precision(10)                
                    .GeneratedBy.Identity();
        DiscriminateSubClassesOnColumn("VehicleTypeId", 0)
            .CustomType<int>()
            .ReadOnly()
            .SqlType("int")
            .Not.Nullable();
        }   
    }
public partial class CarMap : SubclassMap<Car>
{
   public CarMap()
   {
       DiscriminatorValue(1); // 1 = Car
       Map(x => x.MaxSpeed)    
        .Column("MaxSpeed")
        .CustomType("Decimal")
        .Access.Property()
        .Generated.Never()
        .Default(@"0")
        .Precision(19)
        .Scale(4);
       }
    }

飞机的映射类似于汽车使用 SubclassMap

错误的发生似乎是因为 Envers 正在尝试为两个子 class 创建载具 table。我尝试了 including/excluding 车辆 class 的不同变体进行审核。

我的第一个问题是 Envers 是否支持每个 class 继承使用 table?如果是这样,谁能告诉我 examples/documentation 如何根据 class 为 table 配置它?

谢谢。

我们根据 class 方法同时使用 Envers 和 table,我们通常映射基础 class 然后我们使用 Join table 来定义派生 class 试试这样:

public class VehicleMap : ClassMap<Vehicle>
{
  public VehicleMap() {
   Table("Vehicle");
   Id(_ => _.Id, "VehicleId")...
   DiscriminateSubClassesOnColumn("VehicleTypeId");
   ...
}

和汽车

public class CarMap : SubclassMap<Car>
{
  public CarMap() {
    Table("cars");
    DiscriminatorValue(1);
    Join("cars", part => {
      part.KeyColumn("VehicleId");
      part.Map(x => x.MaxSpeed)  ... 

这相当于 9.1.2 中描述的映射 https://nhibernate.info/doc/nhibernate-reference/inheritance.html

对于 Envers,只需添加包括基数 1 在内的所有类型。

事实证明,我们正在使用 Envers 尚不支持的鉴别器属性来映射我们的 classes。我们的鉴别器列映射到另一个 object/table,而不是基本类型。我们提交了一个小补丁来添加对它的支持。

https://github.com/nhibernate/nhibernate-envers/commit/9ae9555ec5e4d4443d5d5ff18c97bf1685278b8e

我们将鉴别器的插入属性设置为 false,以便 NHibernate 知道该列映射到另一个 class。

https://nhibernate.info/doc/nh/en/index.html#mapping-declaration-discriminator

insert (optional - defaults to true): set this to false if your discriminator column is also part of a mapped composite identifier.

Envers 生成的审核 table 映射不包括此设置,因此当 NHibernate 加载生成的 class 映射时,它尝试为基础 class 和子 classes。这就是导致我们遇到的问题的原因。我们提交的补丁寻找这种类型的映射,然后将 insert="false" 属性添加到鉴别器元素。