The Setup
I am using FluentNHibernate 1.4.0 for my NHibernate 3.3.3-SP1 mappings in a .NET4.0 library. I'm using the "table-per-inheritance" approach for my type hierarchy as follows:
-- Different process types potentially use
-- different types of reference values
CREATE TABLE ProcessTypes
(Id INT PRIMARY KEY)
-- Contains reference values for value comparisons
CREATE TABLE ProcessReferenceValues
(Id INT PRIMARY KEY IDENTITY(1,1),
ProcessTypeId INT FOREIGN KEY REFERENCES ProcessTypes(Id),
FloatReferencesValue FLOAT NULL,
IntReferenceValue INT NULL)
// POCOs
class ProcessReferenceValues
{
public virtual int Id { get; set; }
public virtual ProcessTypes ProcessType { get; set; }
public virtual float? FloatReferenceValue { get; set; }
public virtual int? IntReferenceValue { get; set; }
}
class IntProcessReferenceValues : ProcessReferenceValues { }
class FloatProcessReferenceValues : ProcessReferenceValues { }
enum ProcessTypeName : int
{
IntProcess = 1,
FloatProcess = 2
}
class ProcessTypes
{
public virtual int Id { get; set; }
public virtual ProcessTypeName Name { get; set; }
}
// FluentNHibernate Mappings
class ProcessReferenceValuesMap
: FluentNHibernate.Mapping.ClassMap<ProcessReferenceValues>
{
public ProcessReferenceValuesMap()
{
string processTypeId = "ProcessTypeId";
this.Id(x => x.Id);
this.Map(x => x.FloatReferenceValue).Nullable();
this.Map(x => x.IntReferenceValue).Nullable();
// Here is the tricky bit
this.References(x => x.ProcessType, processTypeId);
this.DiscriminateSubClassesOnColumn(processTypeId);
}
}
class IntProcessReferenceValuesMap
: FluentNHibernate.Mapping.SubclassMap<IntProcessReferenceValues>
{
public IntProcessReferenceValuesMap()
{
this.DiscriminatorValue((int)ProcessTypeName.IntProcess);
}
}
class FloatProcessReferenceValuesMap
: FluentNHibernate.Mapping.SubclassMap<FloatProcessReferenceValues>
{
public FloatProcessReferenceValuesMap()
{
this.DiscriminatorValue((int)ProcessTypeName.FloatProcess);
}
}
class ProcessPeriodTypesMap : FluentNHibernate.Mapping.ClassMap<ProcessPeriodTypes>
{
public ProcessPeriodTypesMap()
{
this.ReadOnly();
this.Id(x => x.Id, "id");
this.Map(x => x.Name, "id").ReadOnly().CustomType<PeriodTypeName>();
}
}
The Problem
While reading from the database works like a charm - the appropriate sub classes are selected correctly - saving a new process reference value gives me an exception:
// Reading
var processType =
(from type in session.Query<ProcessTypes>()
where type.Name == ProcessTypeName.IntProcess
select type).FirstOrDefault(); // OK, finds the IntProcess
var referenceValues =
(from val in session.Query<ProcessReferenceValues>()
select val).ToList(); // OK, finds the appropriate subclasses
// Inserting
var processType = new ProcessTypes
{
Id = (int)ProcessTypeName.IntProcess
};
var referenceValue = new ProcessReferenceValues
{
FloatReferenceValue = 0.7f,
IntReferenceValue = null,
ProcessType = processType // Needs the appropriate ProcessType
};
session.Save(referenceValue); // <- BOOM!
Error dehydrating property value for ProcessReferenceValues.ProcessType Invalid Index 2 for OleDbParameterCollection with Count=2. bei System.Data.OleDb.OleDbParameterCollection.RangeCheck(Int32 index) bei System.Data.OleDb.OleDbParameterCollection.GetParameter(Int32 index) bei System.Data.Common.DbParameterCollection.System.Collections.IList.get_Item(Int32 index) bei NHibernate.Type.Int32Type.Set(IDbCommand rs, Object value, Int32 index) in p:\nhibernate-core\src\NHibernate\Type\Int32Type.cs:Zeile 60. bei NHibernate.Type.NullableType.NullSafeSet(IDbCommand cmd, Object value, Int32 index) in p:\nhibernate-core\src\NHibernate\Type\NullableType.cs:Zeile 182. bei NHibernate.Type.NullableType.NullSafeSet(IDbCommand st, Object value, Int32 index, Boolean[] settable, ISessionImplementor session) in p:\nhibernate-core\src\NHibernate\Type\NullableType.cs:Zeile 122. bei NHibernate.Type.ManyToOneType.NullSafeSet(IDbCommand st, Object value, Int32 index, Boolean[] settable, ISessionImplementor session) in p:\nhibernate-core\src\NHibernate\Type\ManyToOneType.cs:Zeile 50. bei NHibernate.Persister.Entity.AbstractEntityPersister.Dehydrate(Object id, Object[] fields, Object rowId, Boolean[] includeProperty, Boolean[][] includeColumns, Int32 table, IDbCommand statement, ISessionImplementor session, Int32 index) in p:\nhibernate-core\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs:Zeile 2410.
As always in hard times I summoned the gooragle and the problem seems to be that the this.DiscriminateSubClassesOnColumn(processTypeId)
adds a conflict with the this.References(x => x.ProcessType, processTypeId)
mapping. When I remove the former the insert is successful but I want the subclass mapping AND I also need to be able to set the ProcessReferenceValues.ProcessType
when adding new instances of ProcessReferenceValues
to distinguish the subclasses.
The Question
Is it possible to discriminate subclasses on a column and at the same time referencing that same column on the same type?
Help very much appreciated, there's got to be a way to do this ...
thx in advance!
int referencetype
in ProcessReference table suffice? – Firo