General example:
Abstract mapped class A. Abstract mapped class B : A. B has a property of type int (or whatever you want.) Mapped class C : A.
Abstract mapped class D has a property of type A. Mapped class E : D. Has a property of type B.
Save E to the database. Retrieve it and attempt to access B.int from E. throws "InvalidCastException: Unable to cast object of type 'AProxy' to type 'B'.
Using FluentNhibernate: 1.3.0 Nhibernate: 3.2.0.4
Actual stripped down example:
BaseTemplate Table:
USE [DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [temp].[BaseTemplate](
[ID] [int] IDENTITY(1,1) NOT NULL,
CONSTRAINT [PK_BaseTemplate] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
MiddleTemplate Table:
USE [DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [temp].[MiddleTemplate](
[ID] [int] NOT NULL,
[MiddleTemplateProperty] [int] NULL,
CONSTRAINT [PK_MiddleTemplate] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [temp].[MiddleTemplate] WITH CHECK ADD CONSTRAINT [FK_MiddleTemplate_BaseTemplate] FOREIGN KEY([ID])
REFERENCES [temp].[BaseTemplate] ([ID])
GO
ALTER TABLE [temp].[MiddleTemplate] CHECK CONSTRAINT [FK_MiddleTemplate_BaseTemplate]
GO
LastTemplate Table:
USE [DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [temp].[LastTemplate](
[ID] [int] NOT NULL,
[LastTemplateProperty] [int] NULL,
CONSTRAINT [PK_LastTemplate] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [temp].[LastTemplate] WITH CHECK ADD CONSTRAINT [FK_LastTemplate_BaseTemplate] FOREIGN KEY([ID])
REFERENCES [temp].[BaseTemplate] ([ID])
GO
ALTER TABLE [temp].[LastTemplate] CHECK CONSTRAINT [FK_LastTemplate_BaseTemplate]
GO
BaseTemplateInstance table:
USE [DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [temp].[BaseTemplateInstance](
[ID] [int] IDENTITY(1,1) NOT NULL,
[TemplateID] [int] NOT NULL,
CONSTRAINT [PK_BaseTemplateInstance] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [temp].[BaseTemplateInstance] WITH CHECK ADD CONSTRAINT [FK_BaseTemplateInstance_BaseTemplate] FOREIGN KEY([TemplateID])
REFERENCES [temp].[BaseTemplate] ([ID])
GO
ALTER TABLE [temp].[BaseTemplateInstance] CHECK CONSTRAINT [FK_BaseTemplateInstance_BaseTemplate]
GO
LastTemplateInstance table:
USE [DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [temp].[LastTemplateInstance](
[ID] [int] NOT NULL,
CONSTRAINT [PK_LastTemplateInstance] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [temp].[LastTemplateInstance] WITH CHECK ADD CONSTRAINT [FK_LastTemplateInstance_BaseTemplateInstance] FOREIGN KEY([ID])
REFERENCES [temp].[BaseTemplateInstance] ([ID])
GO
ALTER TABLE [temp].[LastTemplateInstance] CHECK CONSTRAINT [FK_LastTemplateInstance_BaseTemplateInstance]
GO
Classes:
public abstract class BaseTemplate
public abstract class MiddleTemplate : BaseTemplate
{
public virtual int MiddleTemplateProperty { get; set; }
}
public class LastTemplate : MiddleTemplate
{
public virtual int LastTemplateProperty { get; set; }
}
public abstract class BaseTemplateInstance
{
public virtual BaseTemplate Template { get; set; }
protected BaseTemplateInstance() {}
protected BaseTemplateInstance(BaseTemplate template) : this()
{
Template = template;
}
}
public class LastTemplateInstance : BaseTemplateInstance
{
protected LastTemplateInstance() {}
public LastTemplateInstance(LastTemplate template)
:base(template) {}
public virtual int MiddleTemplateProperty { get { return ((MiddleTemplate) Template).MiddleTemplateProperty; } }
}
Mappings:
public class BaseTemplateMap : ClassMap<BaseTemplate>
{
public BaseTemplateMap()
{
Table("temp.BaseTemplate");
// Unique Identifier
Id(x => x.Id, "ID")
.GeneratedBy.Identity();
}
}
public class MiddleTemplateMap : SubclassMap<MiddleTemplate>
{
public MiddleTemplateMap()
{
Table("temp.MiddleTemplate");
KeyColumn("ID");
Map(x => x.MiddleTemplateProperty)
.Nullable();
}
}
public class LastTemplateMap : SubclassMap<LastTemplate>
{
public LastTemplateMap()
{
Table("temp.LastTemplate");
KeyColumn("ID");
Map(x => x.LastTemplateProperty)
.Nullable();
}
}
public class BaseTemplateInstanceMap : ClassMap<BaseTemplateInstance>
{
public BaseTemplateInstanceMap()
{
Table("temp.BaseTemplateInstance");
// Unique Identifier
Id(x => x.Id, "Id")
.GeneratedBy.Identity();
References(x => x.Template, "TemplateID")
.Not.Nullable();
}
}
public class LastTemplateInstanceMap : SubclassMap<LastTemplateInstance>
{
public LastTemplateInstanceMap()
{
Table("temp.LastTemplateInstance");
// Unique Identifier
KeyColumn("ID");
}
}
Test Example:
[TestFixture]
internal class TempFileTests
{
#region Members
private LastTemplate _entity;
private MappingsRepository _repository;
#endregion // Members
#region SetUp
[TestFixtureSetUp]
public void SetUpFixture()
{
_repository = MappingsRepository.GetInstance();
}
[SetUp]
public void SetUp()
{
_entity = new LastTemplate();
}
#endregion // SetUp
#region Tests
[Test]
public void LastTemplateInstanceMappingsTest()
{
var lastTemplateInstance = new LastTemplateInstance(_entity);
_repository.Save(_entity);
lastTemplateInstance = new PersistenceSpecification<LastTemplateInstance>(_repository.CurrentSession)
.VerifyTheMappings(lastTemplateInstance);
var middleProperty = lastTemplateInstance.MiddleTemplateProperty;
}
#endregion // Tests
#region TearDown
[TearDown]
public void TearDown()
{
if (_entity != null && !_entity.IsNew())
_repository.Delete(_entity);
}
[TestFixtureTearDown]
public void TearDownFixture()
{
_repository.Dispose();
_repository = null;
}
#endregion // TearDown
}
I see your missing the DiscriminateSubClassesOnColumn map on BaseTemplateMap, and DiscriminatorValue map on the MiddleTemplateMap and LastTemplateMap.
Once you let NHibernate know how to identify the type based on descriminator, it should load the right object (ie in your case it's B type), your casting should work.
Look at this sample
The problem arises when trying to access BaseTemplateInstance.Template. If you set this reference in the mapping to NOT lazyLoad, works fine!
The current theory is that trying to access properties from it before it is loaded causes the exception. Making sure it is not lazy loaded, means that it will be loaded, proper casting will be allowed, and properties can be accessed.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.