Trying to make a many-to-many-to-many association.
What I have so far is this:
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; }
}
}
and this is my mapping:
<?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>
Creating a schema generates the following SQL (SqlServer example):
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 )
Any idea what I am doing wrong? From our SQL, we can see it's persisting as IDictionary<string, PersistentClass>
instead of IDictionary<string, ISet<PersistentClass>
, I don't want a many-to-many relationship of many Foo
to many pairs of string
and Persistent
class, where the pair is unique for each Foo
. All three values should create a unique value.
How can I do this?
(note: I included Hibernate tags because the xml mappings for this relationship should be the same whether Hibernate or NHibernate)
Although it creates an unnecessary join, creating another entity can do this, while keep a very similar public interface.
basically:
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
}
}
with mapping as follows:
<?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>