Logo

NHibernate

The object-relational mapper for .NET

Using <set /> in mappings without Iesi.Collections (.Net 4)

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.


Posted Tue, 15 March 2011 03:26:06 PM by jfromainello
Filed under: collections

comments powered by Disqus
© NHibernate Community 2024