Пакет свойств NHibernate / FluentNHibernate - PullRequest
4 голосов
/ 02 мая 2009

Учитывая класс 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]. Транспортное средство будет объединенным корнем (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" (я также не хочу, чтобы свойство Vehicle было в VehicleProperty) ...

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 ]

6 голосов
/ 03 мая 2009

Я полностью согласен с мнением Стефана, и хотя я не могу подтвердить правильность его отображения, буквальный перевод на Свободный 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();
  }
}
4 голосов
/ 03 мая 2009
  1. Не используйте составные идентификаторы.
  2. Обратное означает, что это обратное отношение другого. Если другого нет, просто нет обновлен.
  3. Вы объявили свойство VehicleProperty.Name в качестве первичного ключа. если основной ключ уже инициализирован, NH думает, что оно уже сохранено и поэтому пытается обновить. (вот почему вы получаете исключение.) Вы можете изменил это поведение, но это лучше использовать искусственный первичный ключ или отображение ниже.

Я не знаю, 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>
0 голосов
/ 13 августа 2013

Сначала создайте отдельный класс для составного ПК:

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)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...