没有坚持...... {SUBCLASS} NHibernate与Fluent NHibernate

时间:2009-07-19 21:33:30

标签: nhibernate fluent-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}

2 个答案:

答案 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 - 两个“并行”映射。