NHibernate / FluentNHibernate属性包

时间:2009-05-02 14:23:10

标签: nhibernate fluent-nhibernate

给定Vehicle类和VehicleProperty类......

public class Vehicle
{
    public virtual int Id { get; protected set; }
    public virtual string Registration { get; set; }

    private List<VehicleProperty> _properties = new List<VehicleProperty>();
    public virtual IEnumerable<VehicleProperty> Properties
    {
        get { return _properties; }
        protected set{ _properties = new List<VehicleProperty>(value);}
    }

    public virtual void AddProperty(string name, string value)
    {
        _properties.Add(new VehicleProperty {Name = name, Value = value});
    }
}

public class VehicleProperty
{
    public virtual string Name { get; set; }
    public virtual string Value { get; set; }
}

如何映射这两个类,以便VehicleProperty表具有[VehicleId]和[Name]的复合键。 Vehicle将是一个聚合根(VehicleProperty不在Vehicle类之外访问)。

我已经尝试了所有我能想到的东西(我是NHibernate的新手,所以并不多)

public class VehicleMap : ClassMap<Vehicle>
{
    public VehicleMap()
    {
        Id(x => x.Id);
        Map(x => x.Registration);
        HasMany(x => x.Properties)
            .Inverse()
            .Cascade.All();
    }
}

public class VehiclePropertyMap : ClassMap<VehicleProperty>
{
    public VehiclePropertyMap()
    {
        UseCompositeId()
            .WithKeyProperty(x => x.Name)
            .WithKeyReference(x => x.Vehicle, "Vehicle_Id");
        Map(x => x.Name);
        Map(x => x.Value);
    }
}

这个映射导致下面的sql和StaleStateException“意外的行数:0;期望:1”(我也不想在VehicleProperty上有一个Vehicle属性)......

INSERT INTO "Vehicle" (Registration) VALUES (@p0); select last_insert_rowid(); @p0 = 'AA09CDE'
UPDATE "VehicleProperty" SET Name = @p0, Value = @p1 WHERE Name = @p2 AND Vehicle_Id = @p3; @p0 = 'Colour', @p1 = 'Black', @p2 = 'Colour', @p3 = ''

3 个答案:

答案 0 :(得分:6)

我完全赞同Stefan的观点,虽然我无法证明他的映射的正确性,但是对Fluent NHibernate的字面翻译如下:

public class VehicleMap : ClassMap<Vehicle>
{
  public VehicleMap()
  {
    Id(x => x.Id);
    Map(x => x.Registration);

    HasMany(x => x.Properties)
      .Component(c =>
      {
        c.Map(x => x.Name);
        c.Map(x => x.Value);
      })
      .Cascade.AllDeleteOrphan();
  }
}

答案 1 :(得分:4)

  1. 不要使用复合ID。
  2. 反向意味着,这就是 另一个的反向关系。如果 没有其他人,只是没有 更新。
  3. 您声明了VehicleProperty.Name属性 作为主键。如果是主要的 密钥已经初始化,NH 认为它已经存储了 因此尝试更新。 (这就是你得到例外的原因。)你可以 改变了这种行为,但它确实如此 更好地使用人造初级 密钥或映射波纹管。
  4. 我不知道FluentNHibernate向您展示代码。我可以告诉你它在XML中的外观。

    <class name="Vehicle">
      <id name="Id" generator="native"/>
    
      <property name="Registration"/>
    
      <!-- declare the table Vehicle_Properties for the property Properties -->
      <bag name="Properties" table="Vehicle_Properties" cascade="all-delete-orphan">
    
        <!-- primary key of Vehicle_Properties and foreign key -->
        <key column="Vehicle_FK"/>
    
        <!-- contents of the table: Name and Value -->
        <composite-element class="VehicleProperty">
          <property name="Name"/>
          <property name="Value"/>
        </composite-element>
      </bag>
    
    </class>
    

答案 2 :(得分:0)

首先,为复合PK创建一个单独的类:

public class VehiclePropertyPK
{
  public virtual Vehicle PropertyVehicle { set; get; }
  public virtual string Name { set; get; }

  // You must implement your own GetHasCode and Equals methods
  public override int GetHashCode()
  {
    ...
  }

  public override bool Equals(object o)
  {
    ...
  }
}

然后,以这种方式重构VehicleProperty类:

public class VehicleProperty
{
  public virtual VehiclePropertyPK VehicleCompId { get; set; }
  public virtual string Value { get; set; }
}

最后,地图:

public class VehicleMap : ClassMap<Vehicle>
{
  public VehicleMap()
  {
    Id(x => x.Id);
    Map(x => x.Registration);
    HasMany(x => x.Properties)
        .KeyColumn("Vehicle_Id")
        .Inverse()
        .Cascade.All();
  }
}

public class VehiclePropertyMap : ClassMap<VehicleProperty>
{
  public VehiclePropertyMap()
  {
    CompositeId<VehiclePropertyPK>(x => x.VehicleCompId)
            .KeyReference(y => y.PropertyVehicle , "Vehicle_Id")
            .KeyProperty(y => y.Name, "Name");
    Map(x => x.Value);
  }
}

(NHibernate 3.3.1和FluentNHibernate 1.3.0)