如何映射NHibernate中的多对多三元关系
本文关键字:三元 关系 何映射 映射 NHibernate | 更新日期: 2023-09-27 18:27:19
尝试建立多对多关联。
到目前为止,我所拥有的是:
namespace com.example // Assembly = com.example
{
public class Foo
{
public virtual long Id { get; set; }
public virtual IDictionary<string, ISet<PersistentClass>> MappedCollections { get; set; }
}
public class PersistentClass
{
public virtual long Id { get; protected set; }
public virtual string Prop { get; set; }
}
}
这是我的地图:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="com.example.Foo, com.example">
<id name="Id" type="Int64" generator="hilo" />
<map name="MappedCollections">
<key column="Id" />
<index column="Key" type="String" />
<many-to-many class="com.example.PersistentClass, com.example" />
</map>
</class>
<class name="com.example.PersistentClass, com.example">
<id name="Id" type="Int64" generator="hilo" />
<property name="Prop" />
</class>
</hibernate-mapping>
创建架构会生成以下SQL(SqlServer示例):
if exists (select 1 from sys.objects where object_id = OBJECT_ID(N'[FKC8D94E45A4783B9]') AND parent_object_id = OBJECT_ID('MappedCollections'))
alter table MappedCollections drop constraint FKC8D94E45A4783B9
if exists (select 1 from sys.objects where object_id = OBJECT_ID(N'[FKC8D94E46534DBE0]') AND parent_object_id = OBJECT_ID('MappedCollections'))
alter table MappedCollections drop constraint FKC8D94E46534DBE0
if exists (select * from dbo.sysobjects where id = object_id(N'Foo') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table Foo
if exists (select * from dbo.sysobjects where id = object_id(N'MappedCollections') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table MappedCollections
if exists (select * from dbo.sysobjects where id = object_id(N'PersistentClass') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table PersistentClass
if exists (select * from dbo.sysobjects where id = object_id(N'hibernate_unique_key') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table hibernate_unique_key
create table Foo (
Id BIGINT not null,
primary key (Id)
)
create table MappedCollections (
Id BIGINT not null,
elt BIGINT not null,
Key NVARCHAR(255) not null,
primary key (Id, Key) -- !! WRONG !! should be unique (Id, elt, Key)
)
create table PersistentClass (
Id BIGINT not null,
Prop NVARCHAR(255) null,
primary key (Id)
)
alter table MappedCollections
add constraint FKC8D94E45A4783B9
foreign key (elt)
references PersistentClass
alter table MappedCollections
add constraint FKC8D94E46534DBE0
foreign key (Id)
references Foo
create table hibernate_unique_key (
next_hi BIGINT
)
insert into hibernate_unique_key values ( 1 )
知道我做错了什么吗?从我们的SQL中,我们可以看到它持久化为IDictionary<string, PersistentClass>
而不是IDictionary<string, ISet<PersistentClass>
,我不想要string
和Persistent
类的多对Foo
的多对多关系,其中该对对于每个Foo
都是唯一的。所有三个值都应创建一个唯一值。
我该怎么做?
(注意:我包含了Hibernate标记,因为无论是Hibernate还是NHibernate,这种关系的xml映射都应该相同)
尽管它创建了一个不必要的联接,但创建另一个实体可以做到这一点,同时保持一个非常相似的公共接口。
基本上:
namespace com.example // Assembly = com.example
{
public class Foo
{
public virtual long Id { get; set; }
public virtual ReadOnlyDictionary<string, ISet<PersistentClass>> MappedCollections
{
get
{
return new ReadOnlyDictionary<string, ISet<PersistentClass>>(_mc);
}
}
protected virtual IDictionary<string, PersistentClassSet> _mc { get; set; }
public virtual void InitializeCollection(string key)
{
if (!_mk.ContainsKey(key))
_mc[key] = new PersistentClassSet();
}
}
public class PersistentClass
{
public virtual long Id { get; protected set; }
public virtual string Prop { get; set; }
}
internal class PersistentClassSet : ISet<PersisitentClass>
{
public PersistentClassSet()
{
Proxy = new HashSet<PersistentClass>();
}
protected virtual long Id { get; set; }
protected virtual ISet<PersistentClass> Proxy { get; set; }
public bool Add(PersistentClass item)
{
return Proxy.Add(item);
}
// other ISet implementations delegated to Proxy
}
}
映射如下:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="com.example.Foo, com.example">
<id name="Id" type="Int64" generator="hilo" />
<map name="MappedCollections">
<key column="Id" />
<index column="Key" type="String" />
<many-to-many class="com.example.PersistentClassSet, com.example" />
</map>
</class>
<class name="com.example.PersistentClass, com.example">
<id name="Id" type="Int64" generator="hilo" />
<property name="Prop" />
</class>
<class name="com.example.PersistentClassSet, com.example">
<id name="Id" type="Int64" generator="hilo" />
<set name="Proxy">
<key column="Id"/>
<many-to-many class="com.example.PersistentClass, com.example" />
</set>
</class>
</hibernate-mapping>
假设您有一个名为Product(productid,name)的表,和一个称为Bundle(bundleid,name)。现在,Product和bundle可以进行多对多映射。因此,创建一个名为BundleProduct{BundleId,ProductId}的新表。现在Nhibernate映射如下-
ProductMap
{
HasManyToMany(x => x.Bundles).Table("BundleProduct").ParentKeyColumn("ProductId").ChildKeyColumn("BundleId").Cascade.None().Inverse().Not.LazyLoad();
}
BundleMap
{
HasManyToMany(x => x.Products)
.Table("BundleProduct")
.ParentKeyColumn("BundleId")
.ChildKeyColumn("ProductId")
.Cascade.All();
}