1

I am learning nHibernate and I was trying one to many mapping. Here are the two tables Product and Product Type.

namespace NHibernateSample.Models
{
    public class Product
    {
        public virtual Guid Id { get; set; }
        public virtual string Name { get; set; }
        public virtual string Category { get; set; }
        public virtual bool Discontinued { get; set; }
        public virtual IList<ProductType> ProductTypes { get; set; }
    }
}

Here are my mapping XMLs

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
               assembly="NHibernateSample"
               namespace="NHibernateSample.Models">

  <!-- more mapping info here -->
  <class name="Product">
    <id name="Id">
      <generator class="guid" />
    </id>
    <property name="Name" />
    <property name="Category" />
    <property name="Discontinued" />

    <bag name="ProductTypes">
      <key column="ProductID" />
      <one-to-many class="NHibernateSample.Models.ProductType,NHibernateSample" />
    </bag>
  </class>
</hibernate-mapping>

Product type xml:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
               assembly="NHibernateSample"
               namespace="NHibernateSample.Models">

  <!-- more mapping info here -->
  <class name="ProductType">
    <id name="ProductTypeID">
      <generator class="increment"/>
    </id>
    <property name="ProductType1" column="ProductType"/>
    <property name="ProductID" />
    <many-to-one name="Product" class="Product">
      <column name="ProductID" sql-type="int" not-null="true"/>
    </many-to-one>
  </class>
</hibernate-mapping>

The mappings are in the config

mapping assembly="NHibernateSample" /> 

When I try configuring and build session factory

var cfg = new Configuration();
cfg.Configure();
m_SessionFactory = cfg.BuildSessionFactory();

I get the error saying "Association references unmapped class: NHibernateSample.Models.ProductType" but I see the hbm file in the bin folder.

If I add the assembly explicitly,

Assembly thisAssembly = typeof(Product).Assembly;
cfg.AddAssembly(thisAssembly);

I get another error saying "Duplicate collection role mapping NHibernateSample.Models.Product.ProductTypes"

What am I doing wrong ? Is it not the way I should map the foreign keys ? Thanks in advance

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
Ponnapally
  • 88
  • 1
  • 13
  • Are you sure your hbm.xml file is embedded resource http://stackoverflow.com/a/25291907/1679310? – Radim Köhler Oct 15 '16 at 09:04
  • @RadimKöhler I did it for one xml and forgot to do it for the other. Thank you How can I add a Product type when I add a product for the above code – Ponnapally Oct 15 '16 at 09:12
  • Product prod = new Product(); prod.Name = "Q3"; prod.Category = "Audi"; prod.Discontinued = false; session.Save(prod); Here I insert a product. I want to insert some ProductType to the database like prod.ProductTypes = new .... How can I do that ? – Ponnapally Oct 15 '16 at 09:16

1 Answers1

1

The first issue seems to be related to wrong setting of the .hbm.xml file.. which always must have (see e.g. MappingException: No persister for - NHibernate - Persisting an Adapter)

  • xml mapping file is NOT makred as Embedded Resource
  • xml file is not part of .dll which is configured as the mapping source <mapping assembly="MyProject.Data" /> (see configuration)
  • xml file does not have the default suffix .hbm.xml

The second question (in comment)

Here I insert a product. I want to insert some ProductType to the database like prod.ProductTypes = new .... How can I do that

Product prod = new Product(); 
prod.Name = "Q3"; prod.Category = "Audi"; 
prod.Discontinued = false; 
session.Save(prod);  
...

solution is to adjust the mapping of the collection to be using cascading:

<class name="Product">
    <id name="Id">
      <generator class="guid" />
    </id>
    <property name="Name" />
    <property name="Category" />
    <property name="Discontinued" />

    <bag name="ProductTypes" 
      lazy="true" inverse="true" batch-size="25" cascade="all-delete-orphan"
     >
      <key column="ProductID" />
      <one-to-many class="NHibernateSample.Models.ProductType,NHibernateSample" />
    </bag>

</class>

(what are all these settings on the <bag> - check here)

I would adjust this POCO defintion

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

    //public virtual IList<ProductType> ProductTypes { get; set; }
    IList<ProductType> _productTypes;
    public virtual IList<ProductType> ProductTypes
    {
        get { return _productTypes ?? (_productTypes = new List<ProductType>()); }
        set { _productTypes = value; }
    }
}

(that is just to be sure that list is initiated either by NHibernate on load or by us in other cases)

and then we just have to assign both sides

 // product
 Product prod = new Product(); 
 prod.Name = "Q3"; prod.Category = "Audi"; 
 prod.Discontinued = false; 

 // product type
 ProductType productType = new ProudctType();
 ...

 // both sides assigned
 prod.ProductTypes.Add(productType);
 productType.Product = prod;

 session.Save(prod);  

And we also should adjust the mapping to be readonly for value type property

<property name="ProductID" insert="false" update="false" />
<many-to-one name="Product" class="Product">
  <column name="ProductID" sql-type="int" not-null="true"/>
</many-to-one>

To get more details I would not miss this:

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335