Try fast search NHibernate

15 November 2010

ConfORM : Any-to-Many

In the previous post I have asked a help about well known implementation patterns using interfaces in relations. Even if the feedback was zero I’m happy to say that ConfORM is now supporting case-1-2-3-4. In the meaning I was thinking about the case-6.
An interface is implemented by more than one root-entity or no-root-entity, and thus by its own hierarchies, and it is used as a bidirection-one-to-many
To explain the case I’ll use a chunk of Ayende’s nhibernate-blog-model a little bit complicated for the show-case.
public interface ITagable
{
    string Title { get; }
    string Summary { get; }
}

public class Blog : Entity, ITagable
{
    public Blog()
    {
        Tags = new HashSet<Tag>();
    }
    public virtual string Title { get; set; }
    public virtual string Subtitle { get; set; }
    public virtual ICollection<Tag> Tags { get; set; }
    public virtual string Summary
    {
        get { return Subtitle; }
    }
}

public class Post : Entity, ITagable
{
    public Post()
    {
        Tags = new HashSet<Tag>();
    }
    public virtual string Title { get; set; }
    public virtual string Content { get; set; }
    public virtual ICollection<Tag> Tags { get; set; }
    public virtual string Summary
    {
        get { return Content != null ? Content.Substring(0, Content.Length < 300 ? Content.Length : 300) : Content; }
    }
}

public class Tag : Entity
{
    public virtual string Name { get; set; }
    public virtual ITagable TagedItem { get; set; }
}
Let me highlight some things:

  • ITagable is implemented by two root-entities (two different hierarchies).
  • In Blog and in Post the property Summary does not need to be persisted.
  • Blog and in Post has a collection of Tag.
  • Tag has a property of type ITagable where I can assign a Blog or a Post.
The mapping of this domain is a nice exercise and the code to see how will work your mapping is:
public static class Program
{
    private static void Main(string[] args)
    {
        var nhinit = new NHibernateInitializer();
        nhinit.Initialize();
        nhinit.CreateSchema();
        ISessionFactory sf = nhinit.SessionFactory;

        using (ISession s = sf.OpenSession())
        {
            using (ITransaction tx = s.BeginTransaction())
            {
                var blog1 = new Blog();
                blog1.Title = "NHibernate blog.";
                blog1.Subtitle = "Tricks and tips about NHibernate.";
                blog1.Tags.Add(new Tag {Name = "NHibernate", TagedItem = blog1});

                var post1 = new Post();
                post1.Title = "The difference between Get, Load and querying by id";
                post1.Content = "One of the more common mistakes ...";
                post1.Tags.Add(new Tag {Name = "NHibernate", TagedItem = post1});
                post1.Tags.Add(new Tag {Name = "querying", TagedItem = post1});

                s.Save(blog1);
                s.Save(post1);
                tx.Commit();
            }
        }

        using (ISession s = sf.OpenSession())
        {
            using (ITransaction tx = s.BeginTransaction())
            {
                Blog blog1 = (from b in s.Query<Blog>() select b).Single();
                Console.WriteLine("Blog: " + blog1.Title + " Tags:" + blog1.Tags.AsString());
                Post post1 = (from p in s.Query<Post>() select p).Single();
                Console.WriteLine("Post: " + post1.Title + " Tags:" + post1.Tags.AsString());
                tx.Commit();
            }
        }
        using (ISession s = sf.OpenSession())
        {
            using (ITransaction tx = s.BeginTransaction())
            {
                foreach (Tag tag in from t in s.Query<Tag>() select t)
                {
                    Console.WriteLine("Tag: " + tag.Name);
                    Console.WriteLine("  Item   :" + tag.TagedItem.Title);
                    Console.WriteLine("  Summary:" + tag.TagedItem.Summary);
                }
                tx.Commit();
            }
        }

        Console.WriteLine("Work done!");
        Console.ReadLine();
        sf.Close();
        nhinit.DropSchema();
    }

    private static string AsString(this IEnumerable<Tag> tags)
    {
        return string.Join(", ", tags.Select(x => x.Name).ToArray());
    }
}

You can implements the class NHibernateInitializer as you want, what is important is that you have to create the DB using NHibernate without touch it by hands and then, obviously, you have to see right results.

One dream one soul one prize one goal
The mapping using ConfORM is:
public HbmMapping GetMapping()
{
    var domainEntities = new[] {typeof (Blog), typeof (Post), typeof (Tag)};
    var orm = new ObjectRelationalMapper();
    var mapper = new Mapper(orm, new CoolPatternsAppliersHolder(orm));

    orm.Patterns.PoidStrategies.Add(new HighLowPoidPattern(new {max_lo = 100}));
    orm.Patterns.Sets.Add(new UseSetWhenGenericCollectionPattern());
    orm.TablePerClass(domainEntities);

    orm.Cascade<Blog, Tag>(Cascade.All);
    orm.Cascade<Post, Tag>(Cascade.All);

    mapper.Customize<Post>(cm => cm.Property(p => p.Content, pm => pm.Type(NHibernateUtil.StringClob)));

    return mapper.CompileMappingFor(domainEntities);
}


When something exceeds your ability to understand how it works, it becomes magical.
ConfORM a kind of magic.

1 comment: