1
votes

I am new to Nhibernate and I am trying to map a class (Invoice) which has a generic list property using Nhibernate but I keep getting error: "An association from the table InvoiceDetails refers to an unmapped class: System.Int32". Because each invoice has more details I have tought of one to many relation between Invoices and InvoiceDetails table.

Details: a) Invoice class:

public class Invoice
{
    private IList<InvoiceDetail> _invoiceDetails = new List<InvoiceDetail>();

    public virtual int InvoiceID { get; set; }
    public virtual string SerialNumber { get; set; }
    public virtual string Number { get; set; }
    public virtual DateTime InvoiceDate { get; set; }
    public virtual decimal Amount { get; set; }
    public virtual IList<InvoiceDetail> InvoiceDetails
    {
        get { return _invoiceDetails; }
        set { _invoiceDetails = value; }
    }
    public virtual Customer customer { get; set; }
    public virtual Institution Institution { get; set; }
    public virtual Receipt receipt { get; set; }
    public virtual bool IsDeleted { get; set; }
}

b) InvoiceDetail class:

public class InvoiceDetail
{
    public virtual int InvoiceDetailID { get; set; }
    public virtual int InvoiceID { get; set; }
    public virtual string ServiceDescription { get; set; }
    public virtual string Unit { get; set; }
    public virtual int Quantity { get; set; }
    public virtual double Value { get; set; }
    public virtual bool IsDeleted { get; set; }
}

c) Invoice mapping file:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
    assembly="MyProject" namespace="MyProject.Model">
    <class name="Invoice" table="Invoices">
        <id name="InvoiceID" column="InvoiceID" type="int">
            <generator class="native"></generator>
        </id>
        <property name="SerialNumber" column ="InvoiceSerialNumber"/>
        <property name="Number" column ="InvoiceNumber"/>
        <property name="InvoiceDate"/>
        <property name="Amount"/>
        <property name="IsDeleted" />
        <many-to-one name="Institution" column="InstitutionID" />
        <bag name="InvoiceDetails" access="nosetter.camelcase"
            inverse ="true" lazy ="false" cascade="all-delete-orphan">
            <key column="InvoiceID"/>
            <many-to-one class="MyProject.Model.InvoiceDetail, MyProject"/>
        </bag>
    </class>
</hibernate-mapping>

d) InvoiceDetail mapping file:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
    assembly="MyProject" namespace="MyProject.Model">
    <class name="InvoiceDetail" table="InvoiceDetails">
        <id name="InvoiceDetailID" column="InvoiceDetailID" type="int">
            <generator class="native"></generator>
         </id>
         <many-to-one name="InvoiceID" column="InvoiceID" />
         <property name="ServiceDescription"/>
         <property name="Unit"/>
         <property name="Quantity"/>
         <property name="Value"/>
         <property name="IsDeleted" />    
     </class>
 </hibernate-mapping>
1
your many-to-one InvoiceID seems to be wrong. It should be a property. Or the type of property InvoiceID should be like many-to-one Invoice.Institution : a class. (And the name of the property should be changed to Invoice) - jbl

1 Answers

0
votes

Looks pretty good!

Fix InvoiceID

You need to fix the InvoiceDetail.InvoiceID property. With many-to-one properties, you should model them as references to the parent entity instead of just as simple value properties containing an ID. You got it right with Invoice.Institution.

In InvoiceDetail, replace this...

public virtual int InvoiceID { get; set; }

... with this:

public virtual Invoice Invoice { get; set; }

Likewise, in your mappings, replace this...

<many-to-one name="InvoiceID" column="InvoiceID" />

... with this:

<many-to-one name="Invoice" column="InvoiceID" />

Fix Bag

Also, a bag cannot be many-to-one - it should be one-to-many. See the Documentation. Replace this...

<bag name="InvoiceDetails" access="nosetter.camelcase" inverse ="true" lazy ="false" cascade="all-delete-orphan">
  <key column="InvoiceID"/>
  <many-to-one class="MyProject.Model.InvoiceDetail, MyProject"/>
</bag>

... with this:

<bag name="InvoiceDetails" access="nosetter.camelcase" inverse ="true" lazy ="false" cascade="all-delete-orphan">
  <key column="InvoiceID"/>
  <one-to-many class="MyProject.Model.InvoiceDetail, MyProject"/>
</bag>

Caution about Lazy=False

One final note: be careful with lazy="false". If you are intending to improve performance be having NHibernate eagerly fetch those related records, this is not the way to do it. See http://ayende.com/blog/4573/nhibernate-is-lazy-just-live-with-it for an explanation of why this is a problem. Refer to http://nhibernate.info/doc/nh/en/index.html#performance-fetching for the various way to implement this correctly.