Я использую Fluent nHibernate
для своего уровня персистентности в приложении ASP.NET MVC, и я столкнулся с небольшим затруднением.
У меня есть ситуация, когда мне нужно использовать абстракцию для хранения объектов в коллекции, в этой ситуации интерфейс является наиболее логичным выбором, если вы смотрите на чистую перспективу C #.
По существу, объект (Item
) может иметь Requirements
. Требование может быть много вещей. В нативной ситуации с C # я бы просто выполнил это с помощью следующего кода.
interface IRequirement
{
// methods and properties neccessary for evaluation
}
class Item
{
virtual int Id { get; set; }
virtual IList<IRequirement> Requirements { get; set; }
}
Грубый пример. Это прекрасно работает в нативном C # - однако, поскольку объекты должны храниться в базе данных, это становится немного сложнее, чем это. Каждый объект, который реализует IRequirement
, может быть совершенно другим видом объекта. Поскольку nHibernate (или любой другой ORM, который я обнаружил) не может по-настоящему понять, как сериализовать интерфейс , я не могу себе представить, как подойти к этому сценарию. Я имею в виду, я понимаю проблему.
Это не имеет смысла для базы данных / orm. Я тоже полностью понимаю, почему.
class SomeKindOfObject
{
virtual int Id { get; set; }
// ... some other methods relative to this base type
}
class OneRequirement : SomeKindOfObject, IRequirement
{
virtual string Name { get; set; }
// some more methods and properties
}
class AnotherKindOfObject
{
virtual int Id { get; set; }
// ... more methods and properties, different from SomeKindOfObject
}
class AnotherRequirement : AnotherKindOfObject, IRequirement
{
// yet more methods and properties relative to AnotherKindOfObject's intentive hierarchy
}
class OneRequirementMap : ClassMap<OneRequirement>
{
// etc
Table("OneRequirement");
}
class AnotherRequirementMap : ClassMap<AnotherRequirement>
{
//
Table("OtherRequirements");
}
class ItemMap : ClassMap<Item>
{
// ... Now we have a problem.
Map( x => x.Requirements ) // does not compute...
// additional mapping
}
Итак, у кого-нибудь есть идеи? Кажется, я тоже не могу использовать дженерики, поэтому кажется, что создание базового типа Requirement<T>
не подходит. Я имею в виду, что код работает и работает, но ORM не может его понять. Я понимаю, что я спрашиваю здесь, возможно, невозможно, но все, что я могу сделать, это спросить.
Я также хотел бы добавить, что у меня нет большого опыта работы с nHibernate
, только Fluent nHibernate
, но я осознал, что оба сообщества очень хороши, и поэтому я отмечаю это как оба. Но мое отображение в настоящее время на 100% "свободно".
Редактировать
Я действительно обнаружил Программирование интерфейсов при отображении с помощью Fluent NHibernate , которое немного затрагивает этот вопрос, но я все еще не уверен, что оно применимо к моему сценарию. Любая помощь приветствуется.
ОБНОВЛЕНИЕ (02/02/2011)
Я добавляю это обновление в ответ на некоторые опубликованные ответы, так как мои результаты ... немного неловкие.
Принимая советы и проводя дополнительные исследования, я разработал базовый интерфейс.
interface IRequirement
{
// ... Same as it always was
}
и теперь я устанавливаю свое сопоставление классов ..
class IRequirementMap : ClassMap<IRequirement>
{
public IRequirementMap()
{
Id( x => x.Id );
UseUnionSubclassForInheritanceMapping();
Table("Requirements");
}
}
А потом я сопоставляю то, что реализует это. Вот где он становится очень причудливым.
class ObjectThatImplementsRequirementMap : ClassMap<ObjectThatImplementsRequirement>
{
ObjectThatImplementsRequirementMap()
{
Id(x => x.Id); // Yes, I am base-class mapping it.
// other properties
Table("ObjectImplementingRequirement");
}
}
class AnotherObjectThatHasRequirementMap : ClassMap<AnotherObjectThatHasRequirement>
{
AnotherObjectThatHasRequirementMap ()
{
Id(x => x.Id); // Yes, I am base-class mapping it.
// other properties
Table("AnotheObjectImplementingRequirement");
}
}
Это не , что люди предложили, но это был мой первый подход. Хотя я сделал это, потому что получил очень странные результаты. Результаты, которые действительно имеют для меня нет смысла.
Это на самом деле работает ... Вроде
Выполнение следующего кода дает неожиданные результаты.
// setup ISession
// setup Transaction
var requirements = new <IRequirement>
{
new ObjectThatImplementsRequirement
{
// properties, etc..
},
new AnotherObjectThatHasRequirement
{
// other properties.
}
}
// add to session.
// commit transaction.
// close writing block.
// setup new session
// setup new transaction
var requireables = session.Query<IRequirable>();
foreach(var requireable in requireables)
Console.WriteLine( requireable.Id );
Теперь все становится странно. Я получаю результаты ...
1
1
Это не имеет смысла для меня. Это не должно работать. Я даже могу запросить отдельные свойства каждого объекта, и они сохранили свой тип. Даже если я запускаю вставку, закрываю приложение, затем запускаю извлечение (чтобы избежать возможности кэширования), они все равно имеют нужные типы. Но следующее не не работает.
class SomethingThatHasRequireables
{
// ...
public virtual IList<IRequirement> Requirements { get; set; }
}
Попытка добавить в эту коллекцию не удалась (как я и ожидал). Вот почему я в замешательстве.
- Если я могу добавить к универсальному
IList<IRequirement>
в моем сеансе, почему не в объекте?
- Как nHibernate понимает разницу между двумя сущностями с одинаковым Id,
если они оба отображаются как один и тот же тип объекта в одном сценарии, а не в другом?
Может кто-нибудь объяснить мне, что здесь происходит в мире?
Предлагаемый подход заключается в использовании SubclassMap<T>
, однако проблема заключается в количестве идентификаторов и размере таблицы. Я обеспокоен масштабируемостью и производительностью, если несколько объектов (до 8) ссылаются на идентификаторы из одной таблицы. Может кто-нибудь дать мне некоторое представление об этом конкретно?