Домен сопоставления NHibernate "Свойства расширения"? - PullRequest
2 голосов
/ 01 августа 2010

Я хотел бы «расширить» свои доменные классы без необходимости добавлять данные в сами доменные классы. Считайте, что у меня есть следующий класс:

public class Person
{
public virtual int Id { get; private set; }
public virtual string Name { get; set; }
}

И у меня есть следующая таблица в базе данных:

tblPersons
---------------
Id integer 
Name varchar(50)
CreatedBy varchar(50)
CreatedDate datetime

Поэтому я не хочу добавлять «CreatedBy» и «CreatedDate» в мой класс домена, потому что это не имеет никакого отношения к самому домену ...

Можно ли получить эти данные всякий раз, когда я загружаю объект? Я хотел бы использовать это так:

Person person = session.Load<Person>(1);

person.CreatedBy(); <-- CreatedBy is an Extension function
person.CreatedDate(); <-- CreatedDate is an Extension function

Может кто-нибудь указать мне, в каком направлении идти, чтобы осуществить это?

Я думал о следующих возможностях:

  • Реализация собственной ProxyFactory, где я внедряю пользовательский «интерфейс», такой как IUpdateable, хотя кажется, что NHibernate не создает прокси последовательно, иногда он загружает мой класс «прокси-класса», а иногда и загружает «нормальный класс»:

    Person person = session.Load<Person>(2); //this will load my Proxy class of Person just fine
    
    Address address = person.Address; //Somehow this doesn't load a Proxy for Address, but instead loads it normally - seems like it's evaluating "ImmediateLoad", which doesn't load proxies, due to lazy loading... not sure how to make this behave as I want.
    
  • Использование пользовательского PropertyAccessor. Я прочитал кое-что об этом - но, похоже, мне действительно нужно сопоставить это со свойством EXITS для класса домена ... чтобы это не сработало, верно?

  • Так же, как NHibernate «внедряет» код в среду выполнения при создании прокси-классов - возможно, я мог бы сделать то же самое, но вместо этого внедрить «интерфейс» в исходный класс Person?

Ответы [ 2 ]

1 голос
/ 01 августа 2010

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

public abstract class Auditable : IAuditable
{
    public virtual string CreatedBy { get; set; }
    public virtual DateTime CreatedDate { get; set; }
}

public class Person : Auditable {}

Свободное отображение:

public class AuditableClassMap<T> : ClassMap<T> where T: IAuditable
{
    public AuditableClassMap()
    {
        Map(x => x.CreatedBy);
        Map(x => x.CreatedDate);
    }
}

public class PersonMap : AuditableClassMap<Person> {}

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

0 голосов
/ 02 августа 2010

Вот одна идея. Я никогда не реализовывал это, поэтому возьмите его с крошкой соли, пока не проверите его.

Создайте другой класс, который инкапсулирует данные аудита для Person - PersonCreation или чего-то еще.

Дайте ему идентификатор, дату создания и свойство by-by, а также свойство для идентификатора Person (я не вижу необходимости ссылаться на Person, если только идентификатор не является публичным, в этом случае вы можете захотеть WeakReference, чтобы не хранить каждый экземпляр Person в памяти на весь срок службы приложения).

Вам потребуется создать отображение для NHibernate, чтобы получить PersonCreation объекты из таблицы Person.

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

Или ...

В классе static, который содержит ваши методы расширения CreatedBy() и CreatedDate(), создайте статический IDictionary<int, PersonCreation> для хранения деталей для каждого Person. Поскольку данные для создания, по-видимому, неизменяемы, нам не нужно беспокоиться о том, что это станет устаревшим.

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

var creation = session.CreateCriteria<PersonCreation>()
    .Add(Restrictions.Eq("PersonId", 1))
    .Future<PersonCreation>();

var person = session.CreateCriteria<Person>()
    .Add(Restrictions.IdEq(1))
    .UniqueResult<Person>();

Вызывая Future<T>(), вы говорите NHibernate не выполнять этот запрос до тех пор, пока сеанс в любом случае не будет добавлен в базу данных.

Как только вы получите результаты, вы можете взять первый результат создания и добавить его в словарь (чтобы методы расширения имели к нему доступ) и вернуть человека.

Когда вы вызываете person.CreatedDate(), метод может просто извлечь данные из словаря, используя идентификатор переданного параметра Person или самого Person.

...