4

I'm using nHibernate and trying to add some master-detail data. The database diagram is attached here. Database diagram

The following is the code for adding a category along with two products:

//Category
namespace Sample.CustomerService.Domain
{

    public class Category {
        public Category() {
            Products = new List<Product>();
        }
        public virtual int CategoryID { get; set; }
        public virtual IList<Product> Products { get; set; }
        public virtual string Name { get; set; }
        public virtual string Unit { get; set; }

        public virtual void AddProduct(Product product)
        {
            Products.Add(product);
        }
    }
}

//CategoryMap
namespace Sample.CustomerService.Domain
{

    public class CategoryMap : ClassMap<Category> {

        public CategoryMap() {
            Table("Category");
            LazyLoad();
            Id(x => x.CategoryID).GeneratedBy.Identity().Column("CategoryID");
            Map(x => x.Name).Column("Name").Not.Nullable().Length(50);
            Map(x => x.Unit).Column("Unit").Not.Nullable().Length(3);
            HasMany(x => x.Products).KeyColumn("CategoryID");
        }
    }
}

//--------------------------------------------------------------------------------------------
//Product
namespace Sample.CustomerService.Domain
{

    public class Product {
        public Product() {
        }
        public virtual int ProductID { get; set; }
        public virtual Category Category { get; set; }
        public virtual string Name { get; set; }
        public virtual decimal UnitPrice { get; set; }

    }
}

//ProductMap
namespace Sample.CustomerService.Domain {


    public class ProductMap : ClassMap<Product> {

        public ProductMap() {
            Table("Product");
            LazyLoad();
            Id(x => x.ProductID).GeneratedBy.Identity().Column("ProductID");
            References(x => x.Category).Column("CategoryID");
            Map(x => x.Name).Column("Name").Not.Nullable().Length(50);
            Map(x => x.UnitPrice).Column("UnitPrice").Not.Nullable();
        }
    }
}

//----------------------------------------------------------------------------------------------
//Program
namespace WindowsHibernateTest
{
    public partial class TestClass : Form
    {
        public TestClass()
        {
            InitializeComponent();
            CreateNewProduct();
        }

        public void CreateNewProduct()
        {
            try
            {
                var sessionFactory = CreateSessionFactory();
                using (var session = sessionFactory.OpenSession())
                {
                    using (var sqlTrans = session.BeginTransaction())
                    {
                        Category newGold = new Category() { Name = "Gold", Unit = "GRM" };

                        Product ngOrn = new Product() { Name = "Bangles", UnitPrice = 1000.10M };
                        Product ogOrn = new Product() { Name = "Rings", UnitPrice = 2000.10M };

                        AddProductsToCategory(newGold, ngOrn, ogOrn);

                        session.SaveOrUpdate(newGold);

                        sqlTrans.Commit();
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private static ISessionFactory CreateSessionFactory()
        {
            return Fluently.Configure().Database(MsSqlConfiguration.MsSql2005.
                ConnectionString("Data Source=MyDB; Initial Catalog=NHibernateTest; Trusted_Connection=true;")).Mappings(m => m.FluentMappings.AddFromAssemblyOf<Program>()).BuildSessionFactory();

        }

        public static void AddProductsToCategory(Category category, params Product[] products)
        {
            foreach (var product in products)
            {
                category.AddProduct(product);
            }
        }

    }
}

In the line sqlTrans.Commit(), I'm getting the following error:

object references an unsaved transient instance - save the transient instance before flushing. Type: Sample.CustomerService.Domain.Product, Entity: Sample.CustomerService.Domain.Product

I've Googled for quite sometime and didn't get convincing solutions for this. I've tried this, this and this, but could not able to resolve this error. Please help me to resolve this error. Thanks in advance.

Community
  • 1
  • 1
Nagesh
  • 1,288
  • 3
  • 22
  • 46
  • don't know if that is your problem but you need to change the add product method you got there: foreach (var product in products) { category.AddProduct(product); product.Category = category; } – gdoron Nov 08 '11 at 13:32

1 Answers1

5

I think you need to save the products before you save the category because you don't have a Cascade on the HasMany. And you need to change the add product methods to keep the relation

foreach (var product in products)
{
    category.AddProduct(product); 
    product.Category = category;
} 
gdoron
  • 147,333
  • 58
  • 291
  • 367
  • Product is a child of Category. Product cannot be created without category. – Nagesh Nov 08 '11 at 13:41
  • @Nagesh Why is that? you can save it while it's null, anyway you need to changed the relation like I commented and added to my answer. – gdoron Nov 08 '11 at 13:42
  • @Nagesh By the way, I think you need to understand what does inverse and cascase do. http://stackoverflow.com/questions/4883900/what-does-inverse-and-cascade-means-in-nhibernate Is my question about it when I learned NH... GOOD LUCK! – gdoron Nov 08 '11 at 14:04
  • Kindly provide me some links where I can download documentation regarding Hibernate. – Nagesh Nov 09 '11 at 04:34
  • Tutorials that a friend of mine published: http://www.codecovered.net/2011/04/nhibernate-tutorial-part-1-introduction.html – gdoron Nov 09 '11 at 06:40
  • Hi @gdoron, I'm struck with implementing composite key tables in nHibernate. Here is the link http://stackoverflow.com/questions/8062068/nhibernate-error-message-invalid-index-3-for-this-sqlparametercollection-with-c Kindly help me on this. – Nagesh Nov 09 '11 at 09:45