Нет сохранения для ... {SUBCLASS} NHibernate с Fluent NHibernate - PullRequest
1 голос
/ 20 июля 2009

Как разрешить 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);

Кто-нибудь знает, как я могу свободно настроить это? Благодаря.

К вашему сведению - неявное и явное приведение не действует.

Редактировать

Мои сопоставления такие

class SuperModelMap : ClassMap<SuperModel>
{
    public SuperModelMap()
    {
        WithTable("SuperModels");
        Id(x => x.Id);
        Map(x => x.FirstName);
    }
}

Редактировать 2

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

В моей супермодельной карте ...

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}

Ответы [ 2 ]

4 голосов
/ 23 июля 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, чтобы еще больше уменьшить ее - возможно, создание собственного соглашения позволит автоматически сопоставлять такие классы.

1 голос
/ 22 июля 2009

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

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...