I’ve created a new nuget package; “NHibernate.SetForNet4”.
The package is only one file that will be inserted in your project. This class contains the implementation for the Set<T> and SortedSet<T>.
After you install NHibernate.SetForNet4; the only thing you have to do is to add the collection factory to your configuration as follows:
configuration.Properties[Environment.CollectionTypeFactoryClass]
= typeof(Net4CollectionTypeFactory).AssemblyQualifiedName;
this is a sample mapping:
<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateSetForNet4" namespace="NHibernateSetForNet4"> <class name="Person"> <id name="Id"> <generator class="hilo"/> </id> <property name="Name" /> <property name="Age" /> <set name="Tags" access="field.camelcase"> <key column="PersonId" /> <element column="Tag" /> </set> <set name="Childs" access="field.camelcase" cascade="persist" sort="PersonByAgeComparator"> <key column="ParentId" /> <one-to-many class="Person" /> </set> </class> </hibernate-mapping>
this is the class:
public class Person { private readonly ISet<string> tags = new HashSet<string>(); private readonly ISet<Person> childs = new SortedSet<Person>(new PersonByAgeComparator()); public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual int Age { get; set; } public virtual ISet<string> Tags { get { return tags; } } public virtual ISet<Person> Childs { get { return childs; } } }
ISet<T>, HashSet<T> and SortedSet<T> are from System.Collections.Generics (.Net 4).
All these tests are green:
[TestFixture] public class Fixture { private ISessionFactory sessionFactory; private int personId; [TestFixtureSetUp] public void SetUp() { var configuration = new Configuration(); configuration.Properties[Environment.CollectionTypeFactoryClass] = typeof(Net4CollectionTypeFactory).AssemblyQualifiedName; configuration.Configure(); var schemaExport = new SchemaExport(configuration); schemaExport.Execute(true, true, false); sessionFactory = configuration.BuildSessionFactory(); InitializeData(); } private void InitializeData() { using (var s = sessionFactory.OpenSession()) using (var tx = s.BeginTransaction()) { var person = new Person { Name = "Pipo" }; person.Childs.Add(new Person { Name = "Jose", Age = 1 }); person.Childs.Add(new Person { Name = "Juan", Age = 5 }); person.Childs.Add(new Person { Name = "Francisco", Age = 10 }); person.Tags.Add("one"); person.Tags.Add("two"); person.Tags.Add("three"); s.Persist(person); personId = person.Id; tx.Commit(); } } [Test] public void CanGetAPersonWithTags() { using(var s = sessionFactory.OpenSession()) using (s.BeginTransaction()) { var person = s.Get<Person>(personId); person.Tags.Should().Have.SameValuesAs("one", "two", "three"); } } [Test] public void SortedSetShouldWork() { using (var s = sessionFactory.OpenSession()) using (s.BeginTransaction()) { var person = s.Get<Person>(personId); person.Childs .Select(p => p.Age).ToArray() .Should().Have.SameSequenceAs(10, 5, 1); } } [Test] public void LazyLoadShouldWork() { using (var s = sessionFactory.OpenSession()) using (s.BeginTransaction()) { var person = s.Get<Person>(personId); s.Statistics.EntityCount.Should().Be.EqualTo(1); person.Childs.ToArray(); s.Statistics.EntityCount.Should().Be.EqualTo(4); } } }
The implementation of the proxy collections is a copy from the Iesi version. Let me know if you find some bug. The raw code is here.
Note: you still need Iesi.Collections.dll somewhere because nhibernate internals are tied to these collections, but you don’t longer need to reference it in your domain.