如何让NHibernate忽略我模型的子类的额外属性?
class SuperModel { // hot I know
{
public Guid Id { get; private set; }
public string FirstName { get; set; }
}
class SubModel : SuperModel {
public string FavoriteColor { get; set; }
}
我真的只想使用我的存储库存储SuperModel
数据并在其他地方使用FavoriteColor
,但我得
No persister for: SubModel
即使我用我的存储库保存它
void Store(SuperModel model) {
using (var session = Session){
session.SaveOrUpdate(model); // <<<< The exception is thrown here
}
}
以及我使用的其他地方
void WhatToDo(SubModel model) {
doSomething(model.FavoriteColor);
}
我这样用它
var model = new SubModel { FirstName = "Miranda", FavoriteColor = "Green" };
modelRepository.Store(model);
someService.WhatToDo(model);
任何人都知道如何流利配置这个吗?感谢。
FYI-隐式和显式投射无效。
修改
我的映射就像这样
class SuperModelMap : ClassMap<SuperModel>
{
public SuperModelMap()
{
WithTable("SuperModels");
Id(x => x.Id);
Map(x => x.FirstName);
}
}
修改2
我想/我发现我可以做到这一点,但在我的数据库中,我必须有一个虚拟表,这将是低效的。它有效,但必须有更好的方法......
在我的SuperModelMap中......
JoinedSubClass<SubModel>("SubModel", MapSubModel);
private void MapSubModel(JoinedSubClassPart<SubModel> part)
{
// Leave this empty
}
编辑3 我离我很近,但我在选择上仍然会遇到不同的错误。
我试过了。
DiscriminateSubClassesOnColumn("Id")
.SubClass<SubModel>(m => { });
InnerException {“具有id的对象: 5586b075-47f1-49c8-871c-9c4d013f7220 不是指定的子类: 超级用户(鉴别者是: '1000')“} System.Exception {NHibernate.WrongClassException}
答案 0 :(得分:4)
您可以优化此解决方案,使其更具可重用性。据我了解,你不喜欢映射重复。这可以避免:
我创建了一个包含扩展方法的SuperModelMapHelper类:
public static class SuperModelMapHelper
{
public static void MapSuperModel<T>(this ClassMap<T> classMap)
where T : SuperModel
{
classMap.WithTable("SuperModels");
classMap.Id(x => x.Id);
classMap.Map(x => x.FirstName);
}
}
正如您所看到的 - 它是通用的,并且将接受任何SuperModel的子类。然后,有两个映射:
public class SuperModelMap : ClassMap<SuperModel>
{
public SuperModelMap()
{
MapSuperModel();
}
}
public class SubModelMap : ClassMap<SubModel>
{
public SubModelMap()
{
MapSuperModel();
}
}
我使用了扩展方法来保存FluentNHibernate的约定,你可以使它成为简单的静态方法并将类映射作为参数传递。
这段代码:
Guid id;
using (var session = sf.OpenSession())
using (var transaction = session.BeginTransaction())
{
var subModel = new SubModel()
{FavoriteColor = "blue", FirstName = "Jane"};
session.Save(subModel);
id = subModel.Id;
transaction.Commit();
}
using (var session = sf.OpenSession())
using (var transaction = session.BeginTransaction())
{
var superModel = session.Get<SuperModel>(id);
Console.WriteLine(superModel.GetType().Name);
Console.WriteLine(superModel.FirstName);
transaction.Commit();
}
按预期工作 - 类型为SuperClass。请注意,我已经创建了第二个会话。在尝试在保存它的同一个会话中加载实体之前,您必须刷新会话,因为NHibernate会延迟查询执行。
使用此解决方案几乎没有重复。您可以调查FluentNHibernate的AutoMapping功能以进一步减少它 - 也许创建自己的约定会让您自动映射这些类。
答案 1 :(得分:1)
NHibernate假设你想要检索与你持久存在的完全相同的对象。因此,即使您不关心其他属性,也可以关心对象的类型。如果不这样做,最简单的解决方案是制作SubModel对象的浅表副本,但不要创建SubModel对象,而是创建SuperModel对象。
我认为你考虑过这个并且不喜欢它。如果你想避免虚拟表,但可以使用虚拟列,我建议你打电话:
DiscriminateSubClassesOnColumn("dummycolumn")
.SubClass<SubModel>(m => { });
NHibernate将使用此列来存储有关持久对象类型的信息。从db加载对象时,它将是SubModel或SuperModel,具体取决于持久化时的内容。
调用DiscriminateSubClassesOnColumn的解决方案不起作用,因为NHibernate无法根据id列确定要使用哪个类。
另一个想法:我不确定它是否可行,但您可以为SubModel添加另一个映射,与SuperModel完全相同。然后,NHibernate应该将SubModel保存到与SuperModel相同的表中,当您请求对象时,它应该获取SuperModel对象。不幸的是我现在无法测试这个解决方案,也许你可以让它工作。此解决方案中没有SubClass - 两个“并行”映射。