2

I'm using NHibernate and HiLo strategy and my problem is that IDs of objects in collections are not generated on Session.Save() (only on Transaction.Commit()). For example:

ImageGallery imageGallery = imageGalleryRepository.GetById(imgGalleryId);
imageGallery.Images.Add(new Image());
imageGalleryRepository.Save(imageGallery); // Here I need to access ID propery of new image in Images collection but it's 0 until I commit transaction. Can it be done?

Here's the code that I have:

public abstract class Entity
{
    public virtual int Id { get; set; }
}

public class ImageGallery : Entity
{
    public virtual IList<Image> Images { get; set; }
    // ...
}

public class Image : Entity
{
    public string FileName { get; set; }
    public ImageGallery ImageGallery { get; set; }
    // ...
}

Mappings:

public class ImageGalleryMap : ClassMap<ImageGallery>
{
    public ImageGalleryMap()
    {
        Id(x => x.Id).GeneratedBy.HiLo("hibernate_unique_key", "next_hi_image_gallery", "10");
        HasMany(x => x.Images).
            Cascade.All().
            KeyColumn("GalleryId").
            Inverse().
            Fetch.Join();
    }
}

public class GalleryImageMap : ClassMap<GalleryImage>
{
    public GalleryImageMap()
    {
        Id(x => x.Id).GeneratedBy.HiLo("hibernate_unique_key", "next_hi_image", "10");
        Map(x => x.FileName);
        References(x => x.ImageGallery).Column("GalleryId");
    }
}
mlaen
  • 53
  • 5

2 Answers2

2

Session.Save does not necessarily Flush the changes to the database. Session is a unit of work that contains database changes. It does not necessarily post the changes to the database right away. Please take a look at using Session.Flush(). Please read the following for a more detailed description:

http://www.nhforge.org/doc/nh/en/index.html#manipulatingdata-flushing

Edit:

When you have a bidirectional relationship you also want to maintain this from the code perspective. So you would need to do something like this:

ImageGallery imageGallery = imageGalleryRepository.GetById(imgGalleryId);
Image newImage = new Image();
newImage.ImageGallery = imageGallery;
imageGallery.Images.Add(newImage);

imageGalleryRepository.Save(imageGallery);

Generally I use Add/Remove methods in my entities to do this instead of explicitly doing it in the code above.

If this answer or any other answer here helps you please click the check mark marking it as the answer.

Cole W
  • 15,123
  • 6
  • 51
  • 85
  • That's just the thing, I don't want to go to DB yet, I want to get that ID before DB (hence the HiLo). I commit transaction on EndRequestt, but I need that new ID before that. – mlaen May 18 '11 at 06:23
  • You're not supplying your own IDbConnection to NHibernate are you? – Cole W May 18 '11 at 14:59
  • No, I'm only using connection string from web.config `FluentConfiguration fluentConfiguration = Fluently.Configure() .Database(FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("MyConnectionString")))` – mlaen May 18 '11 at 18:59
  • I doscovered that if I add images to gallery that is not yet persisted and call session.Save(galllery) id for both gallery and image will be generated (without Flush or commit!), but if I fetch gallery from DB and add image in it, that image will have ID=0 after session.Save. Why????? – mlaen May 18 '11 at 19:25
  • One thing I'm seeing is that you are not maintaining the bidirectional relationship from within the code. Please look at my example in my edit above. – Cole W May 18 '11 at 19:32
  • I tried that also, I encapsulated that in AddImage method on Gallery, and updated mappings accordingly but still no change. Note in my previous comment that everything works if I instantiate new gallery object, add some images and call session.save. – mlaen May 18 '11 at 21:47
0

cascading changes for an existing object does not happen until you flush and go to the database. if you want to have a new object (the image) associated with the session, you need to add it to the session itself by calling save on the session and passing the new object. when you have a new gallery object you are adding to the session, it does traverse the object graph and add the referenced children.

also (not very important, but just to point out), you don't need to call save for the gallery itself that you already got from the session with getbyid. it's already there in the session and any changes to it will be persisted when the session flushes. save is really more of an operation to add something to the session. it doesn't care if you try to add something that is already there, it just doesn't really do anything.

Dave Rael
  • 1,759
  • 2
  • 16
  • 21