I'm converting the persistence layer fo existing application that uses Linq2Sql to popluate POCO business objects (seems like overkill but that's another story) to Nhibernate, using Fluent Nhibernate to create the mappings from POCO to DB. Everything has been going swimmingly, until it came to setting readonly properties that were classes, where I was getting the error "NHibernate.MappingException : An association from the table Call refers to an unmapped class: System.Object".
I tried commenting code out an narrowed it down to the the Contract property of my call class.
public class CallMap : ClassMap<Call>
{
public CallMap()
{
Table("Call");
Id(x => x.Id).Column("CallId").GeneratedBy.Identity();
Map(x => x.CallTime).Not.Nullable();
Map(x => x.CallType).Nullable().Not.Nullable();
Map(x => x.CalledFrom).Column("Location").Length(50);
Map(x => x.ImportedCallType).Length(50);
Map(x => x.PhoneNumber).Length(20);
Map(x => x.NumberCalled).Length(20);
Map(x => x.UnitsOfTime);
Map(x => x.ActualVolume).Column("Volume").Not.Nullable();
Map(Reveal.Member<Call>("_dateInvoiced")).Column("DateInvoiced");
References(Reveal.Member<Call>("_contract")).Column("ContractId").Not.Nullable();
References(x => x.Tariff).Column("TariffId").Not.Nullable();
}
}
My business classes is:
public class Call : EntityBase
{
private string _displayVolume;
private string _numberCalled;
private Contract _contract;
private DateTime? _dateInvoiced;
protected Call() { }
public Call(Contract contract)
{
_contract = contract;
}
public virtual Contract Contract { get { return _contract; } }
public virtual PlanTariff Tariff { get; set; }
public virtual DateTime CallTime { get; set; }
public virtual string PhoneNumber { get; set; }
public virtual string NumberCalled
{
get
{
if (CallType == CallVolumeUnit.Data)
return "Data";
if (CallType == CallVolumeUnit.Discrete)
return "SMS";
return _numberCalled;
}
set
{
_numberCalled = value;
}
}
public virtual string CalledFrom { get; set; }
/// <summary>
/// AKA Duration property. Should reflect the Duration
/// formula from the Invoice. This gets filled by the DAL
/// But will be calcualted, in the NHibernate version!
/// </summary>
public virtual decimal Volume { get; set; }
public virtual string DisplayVolume
{
get
{
if (CallType == CallVolumeUnit.Time) {
// format
var hours = Math.Floor(Volume);
var minutes = Math.Round((Volume - hours)*60);
return string.Format("{0}:{1:00}", hours, minutes);
}
if (CallType == CallVolumeUnit.Data) {
return string.Format("{0:0.00} MB", Volume);
}
return string.Format("{0:0}", Volume);
}
set { _displayVolume = value; }
}
/// <summary>
/// The Volume as it was imported from the Call Data
/// </summary>
public virtual decimal ActualVolume { get; set; }
public virtual decimal UnitsOfTime { get; set; }
public virtual decimal UnitCost { get; set; }
public virtual decimal Cost { get; set; }
public virtual string ImportedCallType { get; set; }
public virtual CallVolumeUnit CallType { get; set; }
public virtual bool IsInvoiced
{
get { return _dateInvoiced.HasValue; }
}
}
The problem was setting _contract, as seen on the line
References(Reveal.Member<Call>("_contract")).Column("ContractId").Not.Nullable();
Looking at the intellisense I noticed the Member call takes a return type as second argument, so I set that and everything worked.
References(Reveal.Member<Call, Contract>("_contract")).Column("ContractId").Not.Nullable();
It seems that when setting reference types / complex types you need to specify the type, or you’ll get the System.Object error. Makes sense now I know the problem.