Oren Eini

CEO of RavenDB

a NoSQL Open Source Document Database

Get in touch with me:

oren@ravendb.net +972 52-548-6969

Posts: 7,587
|
Comments: 51,218
Privacy Policy · Terms
filter by tags archive
time to read 14 min | 2607 words

I am not going to talk about all the options that NHibernate has for collections, I already did it for <set/>, and most of that are pretty similar. Instead, I am going to show off the unique features of NHibernate’s <map/>, and then some how crazy you can get with it.

Let us start with the simplest possible scenario, a key/value strings collection, which looks like this:

public class User
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IDictionary<string, string> Attributes { get; set; }
}

And the mapping is pretty simple as well:

<class name="User" table="Users">
    <id name="Id">
        <generator class="hilo"/>
    </id>
    <property name="Name"/>

    <map name="Attributes" table="UserAttributesAreBoring">
        <key column="UserId"/>
        <index column="AttributeName" type="System.String"/>
        <element column="Attributevalue" type="System.String"/>
    </map>
</class>

How are we using this? Let us start by writing it to the database:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
    id = session.Save(new User
    {
        Name = "a",
        Attributes = new Dictionary<string, string>
        {
            {"height", "1.9cm"},
            {"x","y"},
            {"is_boring","true, very much so"}
        },
    });
    tx.Commit();
}

Which give us:

image

And when we want to read it, we just use:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
    var user = session.Get<User>(id);
    Console.WriteLine(user.Name);

    foreach (var kvp in user.Attributes)
    {
        Console.WriteLine("\t{0} - {1}", kvp.Key,
            kvp.Value);
    }

    tx.Commit();
}

And the SQL:

image

This simple mapping is quite boring, so let us try to do something a bit more interesting, let us map a complex value type:

public virtual IDictionary<string, Position> FavoritePlaces { get; set; }

// Position is a value type, defined as:
public class Position
{
    public decimal Lang { get; set; }
    public decimal Lat { get; set; }

    public override string ToString()
    {
        return string.Format("Lang: {0}, Lat: {1}", Lang, Lat);
    }
}

Which we can map using:

<map name="FavoritePlaces" table="UsersFavoritePlaces">
    <key column="UserId"/>
    <index column="PlaceName" type="System.String"/>
    <composite-element class="Position">
        <property name="Lang"/>
        <property name="Lat"/>
    </composite-element>
</map>

Using composite-element, we can map value types (types that have no identifiers, and only exists as part of their parent). We can use it using the following code:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
    id = session.Save(new User
    {
        Name = "a",
        FavoritePlaces = new Dictionary<string, Position>
        {
            {"home", new Position{Lang = 10,Lat = 94.4m}},
            {"vacation house", new Position{Lang = 130,Lat = 194.4m}}
        },
    });
    tx.Commit();
}

And that give us:

image

By now you are probably already are familiar with what reading the FavoritePlaces collection would look like, so we won’t bother. Instead, let us look at a more complex example, what happen if we want the key of the map to be a complex value type as well? Let us look at this:

public virtual IDictionary<FavPlaceKey, Position> ComplexFavoritePlaces { get; set; }

// FavPlaceKey is another value type
public class FavPlaceKey
{
    public virtual string Name { get; set; }
    public virtual string Why { get; set; }

    public override string ToString()
    {
        return string.Format("Name: {0}, Why: {1}", Name, Why);
    }
}

We can map this collection as:

<map name="ComplexFavoritePlaces" table="UsersComplexFavoritePlaces" >
    <key column="UserId"/>
    <composite-index class="FavPlaceKey">
        <key-property  name="Name"/>
        <key-property name="Why"/>
    </composite-index>
    <composite-element class="Position">
        <property name="Lang"/>
        <property name="Lat"/>
    </composite-element>
</map>

And using this is pretty simple as well:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
    id = session.Save(new User
    {
        Name = "a",
        ComplexFavoritePlaces = new Dictionary<FavPlaceKey, Position>
        {
            {
                new FavPlaceKey
                {
                    Name = "home",
                    Why = "what do you mean, why?"
                },
                new Position
                {
                    Lang = 123,
                    Lat = 29.3m
                }
            }
        },
    });
    tx.Commit();
}

Which results in:

image

But that still isn’t over, I am happy to say. So far we have dealt only with value types, what about using entities? You can probably guess:

id = session.Save(new User
{
    Name = "a",
    CommentorsOnMyPosts = new Dictionary<User, Post>
    {
        {anotherUser, post1}
    }
});

With the mapping:

<map name="CommentorsOnMyPosts" table="UserCommentorsOnPosts">
    <key column="UserId"/>
    <index-many-to-many column="CommentorUserId" class="User"/>
    <many-to-many class="Post" column="PostId"/>
</map>

Giving us:

image

But how are we going to read it?

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
    var user = session.Get<User>(id);
    Console.WriteLine(user.Name);

    foreach (var kvp in user.CommentorsOnMyPosts)
    {
        Console.WriteLine("\t{0} - {1}", kvp.Key.Name,
            kvp.Value.Title);
    }

    tx.Commit();
}

The resulting SQL is quite interesting:

image

When we load the commentors, we join directly to the posts (value), but we have to use a different query to load the user. This is something that you should be aware of, when using a <map/> with entity key.

I would like to point out that I have still not covered all the options for <map/>, there are even more options (Although, IDictionary<K, IList<V >> is not something that is possible to map, for the problematic SQL statements that would be required to do so).

And, of course, you are free to mix all types as you would like, entity key and value type, or a string to an entity, or a complex value type to an entity.

Happy (n)hibernating… :-)

a

time to read 7 min | 1214 words

I am not going to talk about all the options that NHibernate has for collections, I already did it for <set/>, and most of that are pretty similar. Instead, I am going to show just the unique stuff about NHibernate’s <list//>. While <set/> is an unordered collection, of unique elements, a <list/> is a collection of elements where the order matter, and duplicate elements are allowed (because there is a difference between item A in index 0 and index 4).

Let us look at what it means by looking at the class itself:

public class User
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<Phone> EmergencyPhones { get; set; }
}

And the mapping:

<class name="User" table="Users">
    <id name="Id">
        <generator class="hilo"/>
    </id>
    <property name="Name"/>
    <list name="EmergencyPhones" table="UsersToEmergencyPhones" cascade="all">
        <key column="UserId"/>
        <index column="Position"/>
        <many-to-many column="PhoneId" class="Phone"/>
    </list>
</class>

Note that I am using <many-to-many/> mapping, if I wanted to use the <one-to-many/> mapping, the PhoneId would be located on the Phones table. Now, let us see how we are working with it:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
    session.Save(new User
    {
        Name = "a",
        EmergencyPhones = new List<Phone>
        {
            new Phone{Name = "Pop", Number = "123-456-789"},
            new Phone{Name = "Mom", Number = "456-789-123"},
            new Phone{Name = "Dog", Number = "789-456-123"},
        }
    });
    tx.Commit();
}

This will produce the following SQL:

image

And now, what happen if we want to read it? Here is the code:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
    var user = session.Get<User>(id);
    foreach (var emergencyPhone in user.EmergencyPhones)
    {
        Console.WriteLine(emergencyPhone.Number);
    }
    tx.Commit();
}

And the generated SQL:

image 

What happen if we update the list? Let us see the code (anyone is reminded in CS 101?):

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
    var user = session.Get<User>(id);
    user.EmergencyPhones.Add(new Phone{Name = "Cat", Number = "1337-7331"});
    var temp = user.EmergencyPhones[2];
    user.EmergencyPhones[2] = user.EmergencyPhones[0];
    user.EmergencyPhones[0] = temp;
    tx.Commit();
}

Which result in:

image

Beware of holes in the list! One thing that you should be careful about is something removing an entry from the list without modifying all the other indexes of the list would cause… problems.

If you were using Hibernate (Java), you would get an exception and that would be it. NHibernate, however, is much smarter than that, and will give you a list back, with one caveat. Let us say that we have the following data in the database:

image

Note that we don’t have a row in position #2. When we load the list, we will get: [ phone#3, phone#2, null, phone#4 ]

A lot of the time, we are processing things like this:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
    var user = session.Get<User>(id);
    foreach (var emergencyPhone in user.EmergencyPhones)
    {
        Console.WriteLine(emergencyPhone.Number);
    }
    tx.Commit();
}

When this code will encounter a hole in the list, it is going to explode in an unpleasant way. You should be aware of this possibility and either protect yourself from it or make sure that whenever you delete from a list, you will rearrange the list so there are no holes in it.

time to read 3 min | 420 words

This is a common question that I get asked, what is better? What should I use? The actual answer is complex, and some of it, at least, depends on personal preferences. More than that, it also depends on the type of queries that you have.

In general, all queries fall into one of the following distinctions:

  • Select by Id
    • select * from Blogs where id = @id
  • Select by fixed criteria (parameters may change, but the actual query itself is fixed)
    • select top 10 * from Posts where PublishDate <= @today order by PublishDate desc
  • Select by dynamic criteria
    • select * from SupportTickets where Title like @title
    • select * from SupportTickets join Resolutions on … where SupportTickets.Title = @title and Resulotions.Status = ‘Resolved’

The first is usually best served by using Get or Load, since they also check NHibernate’s caches and are intended to handle just this scenario.

The second is by far the most common, and it represent perform some kind of a query (not by id) using fixed logic. We may change the parameter values, but the query shape itself is fixed and cannot be changed. This is usually best served by using HQL. HQL is how NHibernate exposes most of its power, and it allow you to operate on your domain model using set based, object oriented, language. Its similarity to SQL means that it is often very intuitive when it comes the time to write and read it.

Its biggest weakness, however, is when you want to perform queries using some dynamic criteria. For example, if you want to have a search page with multiple optional search fields. For that scenario, we have the Criteria API, which allow us to dynamically, painlessly and easily compose queries.

There is also a slightly different side to that, since we can dynamically create queries, the Criteria API also allow us to programmatically create queries, which is very useful for things like query compositions, dynamically enhancing queries, etc.

Beyond those rough guidelines, you have to consider that HQL expose by far the most of NHibernate’s capabilities, but that the Criteria API is almost as complete. The rest is just a matter of personal taste.

FUTURE POSTS

  1. RavenDB & Ansible - 5 days from now
  2. RavenDB & Distributed Debugging - 8 days from now

There are posts all the way to Jul 17, 2025

RECENT SERIES

  1. Production postmorterm (2):
    11 Jun 2025 - The rookie server's untimely promotion
  2. Webinar (7):
    05 Jun 2025 - Think inside the database
  3. Recording (16):
    29 May 2025 - RavenDB's Upcoming Optimizations Deep Dive
  4. RavenDB News (2):
    02 May 2025 - May 2025
  5. Production Postmortem (52):
    07 Apr 2025 - The race condition in the interlock
View all series

Syndication

Main feed ... ...
Comments feed   ... ...
}