Clearly I am searching on the wrong keywords.
I have objects Vendor
and Invoice
in an NHibernate project like so:
public class Vendor
{
public string theName { get; set; }
}
public class Invoice
{
public Vendor theVendor { get; set; }
public decimal Amount { get; set; }
}
I have a UnitOfWork style interface with NH VendorRepository
and InvoiceRepository
repositories... these seem to be working.
I can create a Vendor no sweat, sorta like this:
public void CreateVendor(string name)
{
using (var u = new UnitOfWork())
{
var v = new Vendor();
v.theName = name;
u.Vendors.Add(v);
u.Save();
}
}
Creating the Invoice
object, however, requires a reference to Vendor
. I thought this would be as simple as:
public void CreateInvoice(decimal theAmount, string vendorName)
{
using (var u = new UnitOfWork())
{
var i = new Invoice();
i.Amount = theAmount;
var v = u.Vendors.GetByName(vendorName);
i.theVendor = v;
u.Invoices.Add(i);
u.Save();
}
}
However, this does not appear to be the case. Do I need to do some special NHibernate voodoo for this? I'd prefer to keep the NHibernate behind the UnitOfWork interface, but I'd like to cleanly associate the objects with minimal code or confusion.
UPDATE Per request: Mapping file (extra stuff removed) for Vendor:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="DataModel"
namespace="DataModel">
<class name="Vendor" table="Vendors">
<id name="APVendorId">
<generator class="guid" />
</id>
<property name="theName" index="ixVendorName" length="100" not-null="true" column="VendorName" />
</class>
</hibernate-mapping>
and for Invoice:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="C3.DataModel"
namespace="C3.DataModel">
<class name="Invoice" table="Invoices">
<id name="InvoiceId">
<generator class="guid" />
</id>
<one-to-one name="Vendor" class="Vendor" constrained="true" cascade="none" fetch="join" />
<property name="theAmount" column="InvoiceAmount" not-null="true" />
</class>
</hibernate-mapping>
The repository code resembles this:
///<summary>
///Auto-generated NHibernate repository for the domain POCO object <strong>APInvoice</strong>
///</summary>
public partial class NHInvoiceRepository : IInvoiceRepository
{
internal ISession _Session;
internal ITransaction _Transaction;
private bool _IndependentSession;
///<summary>
///Adds a Invoice object to the NHibernate repository.
///</summary>
public void Add(Invoice invoice)
{
_Session.Save(invoice);
}
///<summary>
///Instantiates the repository in standalone (no associated UnitOfWork) mode. This should usually be avoided.
///</summary>
internal NHInvoiceRepository()
{
_Session = NHibernateHelper.OpenSession();
_Transaction = _Session.BeginTransaction();
_IndependentSession = true;
}
///<summary>
///Instantiates the repository as a part of a UnitOfWork pattern.
///</summary>
public NHInvoiceRepository(ISession session, ITransaction transaction)
{
_Session = session;
_Transaction = transaction;
_IndependentSession = false;
}
///<summary>
///Instantiates the repository as a part of a UnitOfWork pattern.
///</summary>
public NHInvoiceRepository(ISession session)
{
_Session = session;
_Transaction = _Session.BeginTransaction();
_IndependentSession = false;
}
///<summary>
///Implements the IDisposable interface.
///</summary>
public void Dispose()
{
_Transaction.Dispose();
_Session.Dispose();
return;
}
///<summary>
///Commits the changes in the repository in standalone (no associated UnitOfWork) mode.
///</summary>
public void Save()
{
if (_IndependentSession)
{
_Transaction.Commit();
_Transaction = _Session.BeginTransaction();
}
}
}
The UnitOfWork code looks like this:
///<summary>
///UnitOfWork Interface. The primary data interface between the data model and the persistence layer.
///</summary>
public partial class NHUnitOfWork : IUnitOfWork
{
private ISession _Session;
private ITransaction _Transaction;
public IVendorRepository Vendors { get; private set; }
public IInvoiceRepository Invoices { get; private set; }
public void Save()
{
Vendors.Save();
Invoices.Save();
_Transaction.Commit();
}
public void Dispose()
{
Vendors.Dispose();
Invoices.Dispose();
_Transaction.Dispose();
_Session.Dispose();
}
public NHUnitOfWork()
{
_Session = NHibernateHelper.OpenSession();
_Transaction = _Session.BeginTransaction();
Vendors = new NHVendorRepository(_Session);
Invoices = new NHInvoiceRepository(_Session);
}
}
The error message I am getting is:
NHibernate.PropertyValueException: not-null property references a null or transient value
I did try changing the one to one to a many-to-one in the mappings, with no different results.
UPDATE on the second recompile, (and rebuilding the db schema) this change worked.
I always have troubles with <one-to-one>
mappings. I suggest to move to <many-to-one unique="true">