views:

1353

answers:

2

Hi there.

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 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?

A: 

I was having the same problem, I found that if you are adding a new item into the database then you need to call Save() and if you are updating an item then you need to call Update().

For some reason there seems to be a bug with calling SaveOrUpdate().

Hope this helps

Bijington
It's not a bug -- SaveOrUpdate uses the unsaved value (e.g. default 0 for identity fields) to determine if it's an insert or update. There's no valid unsaved value for this class so it's up to the app. to call insert or update appropriately.
Jamie Ide
+3  A: 

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.

Jamie Ide