Babak Fakhriloo
Babak Fakhriloo

Reputation: 2126

using GUID type as primary key in NHibernate and saving the entity

I am using NH as my data access layer, and as it seems it has problems with GUID type as primary key :

public partial class Member
    {
        public virtual Guid UserId { get; set; }
        public virtual string UserName { get; set; }
    }

 public MemberMapping()
        {
            Id(x => x.UserId).GeneratedBy.GuidComb();
            Map(x => x.UserName).Length(20).Not.Nullable();
        }

as it seems, even when I change UserId to the following mapping:

Id(x => x.UserId).GeneratedBy.Assgined();

and then initialze the UserId my self, the object of type member is not begin saved...

But when I use Int data type for UserId it is being saved properly.

I read wont save to database with guid as id- fluent-nhiberate question and used Save() method for saving the member entity with GUIdD as key, but it does not work!

Thanks for your consideration.

Upvotes: 2

Views: 2973

Answers (2)

Oskar Berggren
Oskar Berggren

Reputation: 5629

The page you link to in your follow-up comment is about creating and injecting the session. It does not mention "transaction" or "commit" at all. You should always use NHibernate transactions. Under default settings, committing the transaction will trigger the session to flush any changes to the database. This is a necessary step, since flushing is the only step where changes are guaranteed to be sent to the database.

More on flushing: http://nhibernate.info/doc/nh/en/index.html#manipulatingdata-flushing

Upvotes: 3

Big McLargeHuge
Big McLargeHuge

Reputation: 16056

This was actually a major oversight on my part. Because my entities were all using native ID generation, they were inserted when they were saved even though I never flushed the transaction. (An exception to the rule. See this excellent explanation: https://stackoverflow.com/a/43567/1015595)

Your Member entity, on the other hand, maps the ID to a Guid. In that case, the objects behave as expected and aren't persisted until the transaction is flushed.

Like Oskar said in his answer, you should begin a transaction before you try to save anything and commit the transaction afterwards. A good practice is to wrap the save in a try-catch statement:

// Adds sample data to our database
public ActionResult Seed()
{
    ...

    StoreRepository.BeginTransaction();

    try
    {
        StoreRepository.SaveOrUpdateAll( barginBasin, superMart );

        StoreRepository.Commit();

        return RedirectToAction( "Index" );
    }
    catch
    {
        StoreRepository.Rollback();

        return RedirectToAction( "Error" );
    }
}

Here are the methods you'll need to add to your repository:

public void BeginTransaction()
{
    Session.BeginTransaction();
}

public void Commit()
{
    Session.Transaction.Commit();
}

public void Rollback()
{
    Session.Transaction.Rollback();
}

You want to keep these methods in the repository so your controller remains testable.

When I wrote that article, I didn't know anything about NH transactions. The thing that tripped me up was this part of the Castle Windsor documentation:

There's one important, although invisible effect of what we just did. By registering the components we didn't just tell Windsor how to create them. Windsor will also take care of properly destroying the instances for us, thus taking care of managing their full lifetime. In layman terms, Windsor will dispose both objects when they are no longer being used. This means it will flush the changes we made to ISession to the database for us, and it will clean up the ISessionFactory. And we get all of this for free.

Pretty misleading if you ask me.

Upvotes: 1

Related Questions