2009-07-19 80 views
1

我如何让NHibernate忽略我的模型的子类的额外属性?没有Persister for ... {SUBCLASS} NHibernate与流利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

你能告诉我们你的映射吗? – 2009-07-20 07:48:43

+0

试图解决我遇到的问题。对于整个页面的其余部分,“热我知道”的评论之后,我只是将代码作为故事阅读,并且无法停止发笑。良好的固体测试案例:) – percent20 2011-11-30 19:04:27

回答

1

NHibernate假定你想检索完全一样的对象,你坚持。所以,即使你不关心其他属性,你可能会关心对象的类型。如果你不这样做,最简单的解决方案是创建SubModel对象的浅表副本,但不是创建SubModel对象,而是创建SuperModel对象。

我假设你想过这个,不喜欢它。如果你想避免虚拟表,但可以与虚拟列活,我建议你拨打:

DiscriminateSubClassesOnColumn("dummycolumn") 
.SubClass<SubModel>(m => { }); 

此列将通过NHibernate的被用来存储持久对象的类型信息。从db加载对象时,它将是SubModel或SuperModel,具体取决于它在持久化时的含义。

您调用DiscriminateSubClassesOnColumn的解决方案无法正常工作,因为NHibernate无法根据id列确定使用哪个类。

另一个想法:我不确定它是否可以工作,但是您可以为SubModel添加另一个映射,与SuperModel完全一样。然后,NHibernate应该将SubModel保存到与SuperModel相同的表中,并且当您请求对象时,它应该获取SuperModel对象。不幸的是,我现在无法测试这个解决方案,也许你可以让它工作。此解决方案中没有子类 - 两个“并行”映射。

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); 
    } 
} 

正如你所看到的 - 它是通用的,将接受任何名模的子类。然后,有两个映射:

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(); 
} 

按预期工作 - 类型是超类。请注意,我创建了第二个会话。在尝试在保存它的同一会话中加载实体之前,您必须刷新会话,因为NHibernate会延迟查询执行。

使用这种解决方案几乎没有重复。您可以调查FluentNHibernate的AutoMapping功能以进一步降低它 - 也许创建自己的约定会让您自动映射这些类。