Нет постоянной поддержки {SUBCLASS} 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 {"Объект с идентификатором: 5586b075-47f1-49c8-871c-9c4d013f7220 не принадлежал к указанному подклассу: SuperUser (Дискриминатор был: '1000')"} System.Exception {NHibernate.WrongClassException}


person Daniel A. White    schedule 19.07.2009    source источник
comment
Можете ли вы показать нам свои карты?   -  person James Gregory    schedule 20.07.2009
comment
Пытаясь решить свою проблему, я наткнулся на это. да, после комментария горячего, я знаю, что для всей остальной части страницы я просто прочитал код как историю и не мог перестать смеяться. Хороший твердый тестовый пример для обучения :)   -  person Buddy Lindsey    schedule 30.11.2011
comment
@ percent20 - тогда проголосуйте!   -  person Daniel A. White    schedule 30.11.2011


Ответы (2)


NHibernate предполагает, что вы хотите получить в точности тот же объект, который вы сохраняете. Итак, даже если вам не нужны дополнительные свойства, вам может быть важен тип объекта. Если вы этого не сделаете, самым простым решением было бы сделать неглубокую копию объекта SubModel, но вместо создания объекта SubModel создать объект SuperModel.

Я полагаю, вы подумали об этом, и вам это не понравилось. Если вы хотите избежать фиктивной таблицы, но можете жить с фиктивным столбцом, я предлагаю вам позвонить:

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

Этот столбец будет использоваться NHibernate для хранения информации о типе постоянного объекта. Когда вы загружаете объект из базы данных, это будет SubModel или SuperModel, в зависимости от того, что это было на момент сохранения.

Ваше решение с вызовом DiscriminateSubClassesOnColumn не сработало, потому что NHibernate не смог определить, какой класс использовать, на основе столбца id.

Другая идея: я не уверен, что это сработает, но вы можете добавить еще одно сопоставление для подмодели, точно такое же, как для супермодели. Затем NHibernate должен сохранять SubModel в той же таблице, что и SuperModel, и когда вы запрашиваете свой объект, он должен получать объект SuperModel. К сожалению, я не могу сейчас протестировать это решение, возможно, вы сможете заставить его работать. В этом решении нет подкласса - два «параллельных» сопоставления.

person maciejkow    schedule 22.07.2009
comment
Хорошо, я заставил его работать, но теперь он возвращает подмодель. Любой способ остановить это? - person Daniel A. White; 22.07.2009
comment
Ваша идея верна, но ее нельзя будет использовать повторно. - person Daniel A. White; 22.07.2009

Вы можете усовершенствовать это решение, чтобы сделать его более пригодным для повторного использования. Насколько я понимаю, вам не нравится дублирование карт. Этого можно избежать:

Я создал класс 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 откладывает выполнение запроса.

При использовании этого решения очень мало дублирования. Вы можете исследовать функцию AutoMapping в FluentNHibernate, чтобы еще больше уменьшить ее - возможно, создание собственного соглашения позволит вам автоматически отображать такие классы.

person maciejkow    schedule 23.07.2009