NHibernate / FluentNHibernateプロパティバッグ
-
03-07-2019 - |
質問
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; }
}
2つのクラスをマッピングして、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&quot; Unexpected row count:0;予想:1&quot; (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 = ''
解決
- 複合IDは使用しないでください。
- 逆は、これが 他の逆関係。もし 他に誰もいません 更新されました。
- 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>
他のヒント
Stefanのポイントには完全に同意します。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();
}
}
最初に、複合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)
所属していません StackOverflow