burnt1ce
burnt1ce

Reputation: 14897

Nhibernate: one-to-many relationship is causing GenericADOException

I'm getting the following exceptions and I'm pretty sure it has something to do with the one-to-many relationship between category and product. What's wrong?

Nhibernate.Exceptions.GenericADOException {"could not execute batch command.[SQL: SQL not available]"}

InnerException: {"The INSERT statement conflicted with the FOREIGN KEY constraint \"FK1F94D86A1B57B09E\". The conflict occurred in database \"SimpleNhibernate\", table \"dbo.Category\", column 'Id'.\r\nThe statement has been terminated."}

Program.cs

class Program
{
    private static ISessionFactory _sessionFactory;
    private static Configuration _configuration;

    static void Main(string[] args)
    {

        _configuration = new Configuration();
        _configuration.Configure();
        _configuration.AddAssembly(typeof(Product).Assembly);
        _sessionFactory = _configuration.BuildSessionFactory();

        var schema = new SchemaExport(_configuration);
        schema.Drop(true, true);
        schema.Create(true, true);

        AddCategory(new Category("Phone"));
        AddCategory(new Category("Smart Phone"));

        using (ISession session = NHibernateHelper.OpenSession())
        {
            var categories = session.QueryOver<Category>().List();                
            foreach (var category in categories)
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    session.Save(new Product("iPhone", category));      
                    transaction.Commit(); 


                }
            }
        }

    }

    private static void AddCategory(Category product)
    {
        using (ISession session = NHibernateHelper.OpenSession())
        using (ITransaction transaction = session.BeginTransaction())
        {
            session.Save(product);
            transaction.Commit();
        }
    }
}

Category.cs

using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Iesi.Collections.Generic;
namespace SimpleNhibernate
{
    public class Category
    {
        public virtual Guid Id { get; set; }
        public virtual string Name { get; set; }
        public virtual ISet<Product> Products { get; set; }
        public virtual bool Discontinued { get; set; }

        public Category() { }

        public Category(string name)
        {
            Name = name;
        }
    }
}

Category.hbm.xml

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="SimpleNhibernate"
                   namespace="SimpleNhibernate">

  <class name="Category">
    <id name="Id">
      <generator class="guid" />
    </id>
    <property name="Name" />
    <set name="Products" inverse="true" >
      <key column="Id" />
      <one-to-many class="Product"/>
    </set>
    <property name="Discontinued" />
  </class>

</hibernate-mapping>

Product.hbm.xml

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" 
                   assembly="SimpleNhibernate" 
                   namespace="SimpleNhibernate">

  <class name="Product">
    <id name="Id">
      <generator class="guid" />
    </id>
    <property name="Name" />
    <many-to-one name="Category" column="CategoryID"></many-to-one>
    <property name="Discontinued" />
  </class>

</hibernate-mapping>

Product.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SimpleNhibernate
{
    public class Product
    {
        public virtual Guid Id { get; set; }
        public virtual string Name { get; set; }
        public virtual Category Category { get; set; }
        public virtual bool Discontinued { get; set; }

        public Product() { }
        public Product(string name, Category category)
        {
            Name = name;
            Category = category;
        }
    }
}

Upvotes: 1

Views: 991

Answers (1)

Radim K&#246;hler
Radim K&#246;hler

Reputation: 123861

The column responsible for a mapping (both directions) is CategoryID in Product table

So the set should have the key as this

 <class name="Category">
    ...
    <set name="Products" inverse="true" >
      <key column="CategoryID" /> // instead of Id

to be the same as in Product mapping

<many-to-one name="Category" column="CategoryID"></many-to-one>

Upvotes: 2

Related Questions