Showing posts with label nhibernate. Show all posts
Showing posts with label nhibernate. Show all posts

Monday, November 19, 2012

NHibernate: One-to-One Mapping With Shared Key

Preface

A reader commented on a different NHibernate post, asking about how one might do some different mappings. This post describes one of those scenarios: One-to-One mappings with a shared key. In this case, the parent entity has a surrogate key. The child is using the same value as its primary key and the same field as the foreign key to the parent.

Code samples for this article are on Github.

The Database

The test project is setup to run against a SQL Server database rather than some in-memory or mocked instance. I've created a quick SQL script to setup the datbase tables. SQL Server 2008 R2 was used for this example. The Express edition should work equally as well. We will be working with two tables:


The UserDetail.UserId is the same value as User.Id. Both are primary keys. There is a one-to-one relationship between the Users table and the UserDetail table. The UserDetail table, you will note, does not have an independent field for the foreign key.

The User Object

The first entity is the User. The User is the parent object. It is defined as follows. The AddDetail method is used to associate the different entities with each other. For example, if we have a new User and a new UserDetail, we can pass the UserDetail into the User.AddDetail() method. This will ensure that the UserDetail is correctly setup as the child of the User.

    public class User
    {
        public virtual long Id { get; set; }
        public virtual string Name { get; set; }
        public virtual UserDetail Detail { get; set; }

        public virtual void AddDetail(UserDetail userDetail)
        {
            Detail = userDetail;
            Detail.AddUser(this);
        }
    }

The User object's mapping is pretty basic. It sets the identity column as being generated by the database. It also sets the one-to-one mapping for the detail.

    public class UserMap : ClassMapping<User>
    {
        public UserMap()
        {
            Table("Users");

            Id(user => user.Id, mapper => mapper.Generator(Generators.Identity));

            Property(user => user.Name);

            OneToOne(user => user.Detail,
                     mapper =>
                     {
                         mapper.ForeignKey("FK_User_Id");
                         mapper.Cascade(Cascade.All);
                     });
        }
    }

The UserDetail Object

Next up is the UserDetail. UserDetail is a child of User, having a one-to-one relationship with its parent. The UserDetail.AddUser() method performs a similar function to the User.AddDetail() method: it helps setup the association between the UserDetail object and a parent User object. The Equals() and GetHashCode() overrides are necessary to accommodate the way we'll be setting up the mapping.

    public class UserDetail
    {
        public virtual long UserId { get; set; }
        public virtual string DriversLicense { get; set; }
        public virtual bool IsDonor { get; set; }
        public virtual User ParentUser { get; set; }

        public virtual void AddUser(User user)
        {
            ParentUser = user;
            UserId = user.Id;
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
                return false;

            if (ReferenceEquals(this, obj))
                return true;

            var a = obj as UserDetail;
            if (a == null)
                return false;

            return a.UserId == UserId;
        }

        public override int GetHashCode()
        {
            unchecked
            {
                var hash = 21;

                hash = hash*37 + UserId.GetHashCode();
                
                return hash;
            }
        }
    }

The UserDetail mapping is a little more involved. Identifier is setup as a composite ID. This allows us to use NHibernates mapper to select the column name and the foreign key value. It also imposes the requirement that we have created the Equals() and GetHashCode() overrides.

    public class UserDetailMap : ClassMapping<UserDetail>
    {
        public UserDetailMap()
        {
            Table("UserDetail");

            ComposedId(mapper => mapper.ManyToOne(o => o.ParentUser, x =>
                                                                     {
                                                                         x.Column("UserId");
                                                                         x.ForeignKey("FK_User_Id");
                                                                     }));

            Property(detail => detail.DriversLicense);
            Property(detail => detail.IsDonor);
        }
    }

Persisting The Entities

One common mistake made when using NHibernate to persist related entities is to not set the relevant properties. In this case, the UserDetail.ParentUser property must be set, so that NHibernate can get the value of the ID property. I then to use a setter method to ensure any values are correctly set. In this case, it's the UserDetail.AddUser() method.

The tests file in the example solution gives two examples for persisting the entities to the database. It highlights how to ensure the critical step which happens just after creating the detailToBeSaved object.

        [TestMethod]
        public void SavingAUserWithADetailObject()
        {
            var userToBeSaved = Builder<User>.CreateNew()
                .With(user1 => user1.Id = 0)
                .Build();
            var detailToBeSaved = Builder<UserDetail>.CreateNew().Build();
            // Don't forget the next line...
            userToBeSaved.AddDetail(detailToBeSaved);

            object save;

            using (var txn = session.BeginTransaction())
            {
                save = session.Save(userToBeSaved);
                txn.Commit();
            }

            var loadedUser = session.Get<User>(save);

            loadedUser.ShouldHave().AllPropertiesBut(user => user.Id).EqualTo(userToBeSaved);
            loadedUser.Detail.ShouldHave().AllProperties().EqualTo(detailToBeSaved);

            using (var txn = session.BeginTransaction())
            {
                session.Delete(loadedUser);
                txn.Commit();
            }
        }

A Common Problem

It's pretty common to forget to initialize the child object before persisting. In this case, the UserDetail cannot exist without its parent User. However, if we do not setup the properties on the UserDetail via the AddUser() method or some other means, NHibernate won't know how to associate things. This results in an exception like the following:
Test method Prabu.Tests.OneToOneTests.SavingAUserWithADetailObject threw exception: NHibernate.Exceptions.GenericADOException: could not execute batch command.[SQL: SQL not available] ---> System.Data.SqlClient.SqlException: Cannot insert the value NULL into column 'UserId', table 'Prabu.dbo.UserDetail'; column does not allow nulls. INSERT fails. The statement has been terminated.
This happens because NHibernate has no way to figure out what it should be inserting in the UserDetail.UserId field. You can prove this by commenting out the lines of the AddUser() method, and running the test.

Summary

It really is easier and better to just have a surrogate key with which to work. NHibernate is flexible enough to accommodate times when the world isn't perfect. I hope this helped show how to get around one of those sticky situations.

Tuesday, March 6, 2012

TDD: NSubstitute, CQRS, and abstract classes...

Preface

I'm a fan of CQRS. It's a great way to separate concerns when dealing with data. In fact, I'm a pretty big fan of the command pattern as a whole. One of the big issues I've faced with using this pattern is unit testing the queries. (Note: this is a pretty contrived example, but it should get the idea across.) Sample code can be found on Github.

The Problem

I want to implement some kind of cache object, and I want to use CQRS in fetching the entities from the database. To top it off, I want to unit test the cache. Here's a look at the cache (and yes, I know it's not really caching anything):

    public class ReportCache
    {
        private readonly ISession session;
        private readonly GetReportByDateAndType getReportByDateAndType;

        public ReportCache(ISession session, GetReportByDateAndType getReportByDateAndType)
        {
            this.session = session;
            this.getReportByDateAndType = getReportByDateAndType;
        }

        public Report GetReportByDateAndType(DateTime reportDate, ReportType reportType)
        {
            getReportByDateAndType.ReportDate = reportDate;
            getReportByDateAndType.ReportType = reportType;
            var reports = getReportByDateAndType.Execute(session);

            return reports.First();
        }
    }

The Solution

The hurdle is how to mock out the query object. I've always tried to implement some kind of interface with varying levels of success. Following that approach made it difficult to use/inject the query into whatever object was using it.

I was usually left with an interface supplied in the constructor which had to be downcast to allow access to the properties. Another option would be to supply a factory object, which could create the appropriate query when necessary. The former being a Liskov Substitution Principle violation. The latter adding unnecessary complexity.

One day, I realized I could use abstract classes, and life became a little easier. Let's say we start with the query itself:

    public class GetReportByDateAndType : QueryBase
    {
        public DateTime ReportDate { get; set; }
        public ReportType ReportType { get; set; }

        public override IQueryable<Report> Execute(ISession session)
        {
            return session.Query<Report>()
                .Where(report => report.ReportDate == ReportDate && report.Type == ReportType);
        }
    }

You'll notice that the queries inherit from a base class. This class is an abstract, and enforces that the Execute() method can be overridden. I'm using this similar to an interface. It's a means to define what the queries will look like:

    public abstract class QueryBase
    {
        public abstract IQueryable<Report> Execute(ISession session);
    }

Doing a unit test with this setup, becomes a matter of simply mocking the query. This can be done with a framework or a hand-rolled mock. The following is an example using NSubstitute:

    public static class ReportCacheTests
    {
        public class ReportCacheSpecs : ContextSpecification
        {
            protected ReportCache Sut;
            protected GetReportByDateAndType TestQuery;
            protected ISession TestSession;

            protected override void Context()
            {
                TestSession = Substitute.For<ISession>();
                TestQuery = Substitute.For<GetReportByDateAndType>();
                Sut = new ReportCache(TestSession, TestQuery);
            }
        }

        [TestClass]
        public class MockWithNSubstitute : ReportCacheSpecs
        {
            private Report expectedReport;
            private Report result;
            private DateTime testDate;
            private ReportType testReportType;

            protected override void Context()
            {
                base.Context();

                testDate = new DateTime(2012, 01, 02);
                testReportType = ReportType.Cost;

                expectedReport = new Report
                                     {
                                         ReportId = 42L,
                                     };
                TestQuery.Execute(TestSession)
                    .Returns(new List<Report> { expectedReport }.AsQueryable());
            }

            protected override void BecauseOf()
            {
                result = Sut.GetReportByDateAndType(testDate, testReportType);
            }

            [TestMethod]
            public void TheCacheShouldReturnTheFirstReport()
            {
                result.Should().Be(expectedReport);
            }

            [TestMethod]
            public void TheCorrectParametersShouldBeSetOnTheQuery()
            {
                TestQuery.ReportDate.Should().Be(testDate);
                TestQuery.ReportType.Should().Be(testReportType);
            }
        }
    }

I've posted an example to Github. You'll notice the example also shows how to extend the functionality of the query without using inheritance. I plan on writing a blog about this at a later date. An added bonus is any IoC container can be used to supply the query, so there's no need for a factory.

Thursday, February 2, 2012

NHibernate Samples: Row Versioning with SQL Server Timestamp

Preface

I've recently switched from using FluentNHibernate to NHibernate. The decision was made to reduce the number of dependencies required by a solution. Since NHibernate (3.2+) now includes a means of mapping entities to database tables, I just didn't need to use FNH. The big problem I've run into as a result of the switch is the lack of samples on the 'net. Since I can't do my normal R&D (rip-off and duplicate), I've had to resort to actual learning. These articles are intended as a means to provide me with a way to consolidate what I've copied/learned. They should also serve as a way to give other people a handy reference.

I've also created a solution on github to host the code. Fee free to download it, copy it, recycle it, or ignore it.

The Problem

This post is related to a question on stackoverflow.com, NHibernate 3.2 By Code ClassMapping for Version Property. SQL Server has an 8-byte incremental number, the timestamp, which can be used for row versioning. However, it's not immediately obvious how to map the column in the database to an entity.

Note: DateTime is bad for Timestamp

It's worth noting that a DateTime does not have sufficient resolution to be used as a timestamp. See this stackoverflow question, and this msdn article.

The Solution

Since a SQL timestamp is equivalent to the C# byte[] type, NHibernate needs help making the translation. The solution is using a custom IUserVersionType. Conveniently, there is already an implementation buried within the NHibernate source code: the BinaryTimestamp. Using this class, it's possible to map an entity's property to the table's column.

The custom type

This type tells NHibernate how to handle the conversion between the SQL timestamp type and C# byte[] type.

    public class BinaryTimestamp : IUserVersionType
    {
        #region IUserVersionType Members

        public object Next(object current, ISessionImplementor session)
        {
            return current;
        }

        public object Seed(ISessionImplementor session)
        {
            return new byte[8];
        }

        public object Assemble(object cached, object owner)
        {
            return DeepCopy(cached);
        }

        public object DeepCopy(object value)
        {
            return value;
        }

        public object Disassemble(object value)
        {
            return DeepCopy(value);
        }

        public int GetHashCode(object x)
        {
            return x.GetHashCode();
        }

        public bool IsMutable
        {
            get { return false; }
        }

        public object NullSafeGet(IDataReader rs, string[] names, object owner)
        {
            return rs.GetValue(rs.GetOrdinal(names[0]));
        }

        public void NullSafeSet(IDbCommand cmd, object value, int index)
        {
            NHibernateUtil.Binary.NullSafeSet(cmd, value, index);
        }

        public object Replace(object original, object target, object owner)
        {
            return original;
        }

        public System.Type ReturnedType
        {
            get { return typeof(byte[]); }
        }

        public SqlType[] SqlTypes
        {
            get { return new[] { new SqlType(DbType.Binary, 8) }; }
        }

        public int Compare(object x, object y)
        {
            var xbytes = (byte[])x;
            var ybytes = (byte[])y;
            return CompareValues(xbytes, ybytes);
        }

        bool IUserType.Equals(object x, object y)
        {
            return (x == y);
        }

        #endregion

        private static int CompareValues(byte[] x, byte[] y)
        {
            if (x.Length < y.Length)
            {
                return -1;
            }
            if (x.Length > y.Length)
            {
                return 1;
            }
            for (int i = 0; i < x.Length; i++)
            {
                if (x[i] < y[i])
                {
                    return -1;
                }
                if (x[i] > y[i])
                {
                    return 1;
                }
            }
            return 0;
        }

        public static bool Equals(byte[] x, byte[] y)
        {
            return CompareValues(x, y) == 0;
        }
    }

An example table definition


This is an example table. Note the name of the timestamp column. Our entity will use a differently named property to store the value in memory.
create table Orders
(
 OrderId bigint primary key identity
 ,Comments varchar(max) not null default ''
 ,DatePlaced datetime not null default getdate()
 ,LastModified timestamp not null
)

An example model/entity

    public class Order
    {
        public virtual long OrderId { get; set; }
        public virtual string Comments { get; set; }
        public virtual DateTime DatePlaced { get; set; }
        public virtual byte[] Version { get; set; }

        public override string ToString()
        {
            return string.Format("Order ({0}) - {1}", OrderId, DatePlaced);
        }
    }

An example of the mapping

The version statement contains the instructions for NHibernate. mapper.Generated(VersionGeneration.Always) tells NHibernate that SQL Server will handle generation of the value. mapper.Column("LastModified") tells NHibernate that the name of the column is different from the name of the property. mapper.Type<BinaryTimestamp>() tells NHibernate what class to use in converting the sql timestamp type to a C# byte[] and vice versa.

    public class OrderMap : ClassMapping<Order>
    {
        public OrderMap()
        {
            Table(DatabaseTable.Orders);

            Id(order => order.OrderId, mapper => mapper.Generator(Generators.Identity));
            
            Property(order => order.Comments);
            Property(order => order.DatePlaced);
            
            Version(order => order.Version, mapper =>
                          {
                              mapper.Generated(VersionGeneration.Always);
                              mapper.Column("LastModified");
                              mapper.Type<BinaryTimestamp>();
                          });
        }
    }

Wednesday, November 9, 2011

NHibernate 3.2 One-To-One Mapping with Foreign Key

Preface


Until recently, I'd been using FluentNhibernate to do my entity mappings in code. Recently, I decided to try the Loquacious (in-code) mapping now part of NHibernate. Since the project was already setup with NHibernate, it the mapping classes had to be converted. This was a (fairly) direct process, except for an oddball mapping we had.


The Problem

Using Loquacious (in code) mapping with NHibernate 3.2, we needed to do a one-to-one mapping of entities where the SQL Server tables had a PK<->FK relationship.

Our Design

Our tables looked like...

User
-----------
UserId (PK)
UserName

UserDetail
--------------------
UserDetailId (PK)
UserId (FK / Unique)
Notes

Our entities looked like...
public class UserInfo
{
    public virtual int Id { get; set; }
    public virtual string UserName { get; set; }
    public virtual UserDetail Details { get; set; }
}

public class UserDetail
{
    public virtual int Id { get; set; }
    public virtual UserInfo User { get; set; }
    public virtual string Notes { get; set; }
}

The important thing to note here is that the User entity does not have a List<Details> property. There will only be one UserDetail for any particular User.

What is a One-To-One Relationship?

A one to one mapping shouldn't use a foreign key. Instead, the tables should both use a synchronized primary key (the pk on both tables are the same value:

UserInfo
-----------
UserInfoId (PK)
UserName

UserDetail
-----------------
UserDetailId (PK/FK)
DetailInfo

The Solution

I failed at using Google to find a solution. There were a few mentions on Stack Overflow. One of the how-to articles on nhforge.org did get me started in the right direction. The problem with the article is that it uses xml mapping (didn't want to do that). It does not one of the major headaches I ran into: that when mapped it would fail to insert the dependent entity.

After poking around for some time, I stumbled on the solution (for our case): it was to reference the foreign key in the dependent entity. Our mapping classes turned out to look like the following:

public sealed class UserInfoMap : ClassMapping
{
    public UserInfoMap()
    {
        Table("UserInfos");

        Id(o => o.Id, map =>
        {
            map.Generator(Generators.Identity);
            map.Column("UserInfoId");
        });

        Property(o => o.UserName);

        OneToOne(o => o.Details,
                 map =>
                 {
                     map.PropertyReference(typeof(UserDetail).GetProperty("User"));
                     map.Cascade(Cascade.All);
                 });
    }
}


public class UserDetailMap : ClassMapping
{
    public UserDetailMap()
    {
        Table("UserDetails");

        Id(o => o.Id, map =>
        {
            map.Generator(Generators.Identity);
            map.Column("UserDetailId");
        });

        Property(o => o.Notes);

        ManyToOne(o => o.User,
                  o =>
                  {
                      o.Column("UserId");
                      o.Unique(true);
                      o.ForeignKey("Users_UserDetails_FK1");
                  });
    }
}

Hope this helps someone else...

Monday, October 24, 2011

NHibernate and Missing Castle dll

The Problem

MSbuild does not see a reference to the NHibernate.ByteCode.Castle assembly when building a project. Thus,  it does not copy the file into the output directory. This causes an exception when trying to execute code which relies on NHibernate.

The exception seen is usually something like: Could not load file or assembly 'NHibernate.ByteCode.Castle' or one of its dependencies...


The Solution


Bury a reference to the Castle assembly within your code:

class IncludeCastleDllInBuild : NHibernate.ByteCode.Castle.ProxyFactory
{
    //note : prevents missing dll issue with the Castle dll
}

Wednesday, October 19, 2011

FluentNhibernate and Bidirectional Relations

Preface

My last position had me using FluentNHibernate to handle my object persistence. We were using Oracle as a store. Many of the tables were quite large (100+ columns), and often did not have a primary key. The result was I often didn't have a good opportunity to use FNH's (NH's?) relationship capabilities.

My new position has me introducing FNH to some developers. The project is using SQL Server 2008 as a store, with tables that have primary keys, and other little should-haves.

The Problem

When saving new parents with new children, the children would not have their foreign key updated. The parent would save correctly. When any child object would save the database would throw an exception, because the foreign key constraint (not null) would be violated.

Our Design

Names changed to protect the innocent.

Our design was simple: a record in the database representing a file, and records being held in another table representing records within the file. After a bit of research, we realized that we needed a bi-directional relationship.

public class MyFile
{
    public virtual int MyFileId { get; set; }
    public virtual string FileName { get; set; }
    public virtual IList<Record> Records  { get; set; }
}

public class Record
{
    public virtual int MyRecordId { get; set; }
    public virtual int MyFileId { get; set; }
    public virtual MyFile SourceFile { get; set; }
    public virtual int RecordType { get; set; }
}

Our mapping classes were pretty simple too:

public sealed class MyFileMap : ClassMap<MyFile>
{
    public MyFileMap()
    {
        Table("MyFile");

         Id(o => o.MyFileID, "MyFileID").GeneratedBy.Identity();

        Map(o => o.FileName).Column("FileName");

        HasMany(o => o.Records).KeyColumn("InFileID")
            .Inverse().Cascade.All().AsBag();
    }
}

public sealed class RecordMap : ClassMap<Record>
{
    public WEXTicketRequestDetailMap()
    {
        Table("Record");

        Id(o => o.RecordID, "RecordID").UnsavedValue(0);

        References(o => o.SourceFile)
            .Column("MyFileID").Cascade.All();

        Map(o => o.RecordType).Column("RecordType");
    }
}

We'd create the classes and attempt to save them to the database:

// ... some code
var record = new Record();
var file = new MyFile{ // set some file stuffs here };
file.Records = new List<Record>{ record };
// ... more stuff here, including creating a session and transaction
session.Save(file);

This would result in an exception being thrown, as the foreign key on the Record object wasn't being set.

The Solution

A little searching (okay, a lot of searching) finally led us to a Stack Overflow post. Therein an answer by James Gregory showed us what we were doing wrong: we needed to set the parent entity on the child.

// ... some code
var record = new Record();
var file = new MyFile{ // set some file stuffs here };

record.SourceFile = file; // <-- this is the important part

// ... more stuff here, including creating a session and transaction
session.Save(file);

Once that was done, everything was good.