R – Fluent NHibernate Composite key with Dates

compositedatetimefluent-nhibernatekey

I'm new to NHibernate and am having difficulty with a simple but stuborn error.

I have a table in my DB (MSSQL2008) where the composite key is made up of 2 date columns.

These would represent a time period StartDate and EndDate that is unique for the purposes of my solution.

The table definition is as such:

CREATE TABLE [dbo].[CompositeKeyTab](
[KeyCol1] [date] NOT NULL,
[KeyCol2] [date] NOT NULL,
[Value] [decimal](18, 0) NULL,
CONSTRAINT [PK_CompositeKeyTab] PRIMARY KEY CLUSTERED
(
[KeyCol1] ASC,
[KeyCol2] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

In my domain model I have a corresponding entity:

public class CompositeKeyEnt
{
    public virtual DateTime KeyCol1 { get; set; }
    public virtual DateTime KeyCol2 { get; set; }
    public virtual decimal Val { get; set; }

    public override bool Equals(object obj)
    {
        var compareTo = obj as FinancialDay;
        if (compareTo == null)
            return false;
        return this.GetHashCode() == compareTo.GetHashCode();
    }
    public override int GetHashCode()
    {
        return this.KeyCol1.GetHashCode() ^ this.KeyCol2.GetHashCode();
    }
}

and in my mapping assembly a map:

public class CompositeKeyEntMap: ClassMap<CompositeKeyEnt>
{
    public CompositeKeyEntMap()
    {
        WithTable("CompositeKeyTab");
        UseCompositeId().WithKeyProperty(e => e.KeyCol1, "KeyCol1").WithKeyProperty(e => e.KeyCol2, "KeyCol2");
        Map(e => e.Val, "Value");
    }    
}

Everything compiles OK. But when I try to persist an instance of my class to the DB (like so)

        CompositeKeyEnt cke = new CompositeKeyEnt() { KeyCol1 = DateTime.Now.AddDays(1), KeyCol2=DateTime.Now.AddDays(1), Val = 2.2M };
        CompositeKeyEnt cke1 = new CompositeKeyEnt() { KeyCol1 = DateTime.Now, KeyCol2 = DateTime.Now, Val = 1.1M };
        Repository<CompositeKeyEnt> crep = new Repository<CompositeKeyEnt>();
        crep.SaveOrUpdate(cke);
        crep.SaveOrUpdate(cke1);

I get:

"Unexpected row count: 0; expected: 1"

When Flush() is called on the session.

    public virtual T SaveOrUpdate(T entity)
    {
        using (var context = Session)
        {
            context.SaveOrUpdate(entity);
            context.Flush(); //Exception raised here!!!
        }
        return entity;
    }

What am I doing wrong?

Best Answer

I think the problem is that NHibernate doesn't know what the unsaved value is for your composite key so it tries to issue an update instead of an insert when you call SaveOrUpdate(). I don't see any possibility for you to have a valid unsaved value for this class, so I suggest you modify your repository to implement Save() and Update() separately and call the appropriate method.