0

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

NHibernate.MappingException:无法为类 Demo.Vehicle_AUD 构建插入语句:添加鉴别器时发生故障 ---> System.ArgumentException:此 SQL 构建器中已添加列“VehicleTypeId”

参数名称: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;}
}

表定义:

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 正在尝试为两个子类创建 Vehicle 表。我尝试了包括/排除 Vehicle 类以进行审计的不同变体。

我的第一个问题是 Envers 是否支持每个类继承使用表?如果是这样,谁能指出我如何为每个班级的表格配置它的示例/文档?

谢谢。

4

2 回答 2

0

我们同时使用 Envers 和 table per class 方法,我们通常映射基类,然后我们使用 Join table 来定义派生类尝试以这种方式:

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)  ... 

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

对于 Envers,只需添加所有类型,包括基本类型。

于 2019-09-30T13:17:02.260 回答
0

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

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

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

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

插入(可选 - 默认为 true):如果您的鉴别器列也是映射复合标识符的一部分,则将此设置为 false。

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

于 2019-10-05T16:59:48.337 回答