2012-06-19 2 views
0

В моем домене у меня есть что-то под названием Project, в котором в основном хранится множество простых конфигурационных пропозиций, описывающих, что должно произойти, когда проект получает executed. Когда проект выполняется, он производит огромное количество LogEntries. В моем приложении мне нужно проанализировать эти записи журнала для данного Проекта, поэтому мне нужно иметь возможность частично последовательно загружать часть (временные рамки) записей журнала из базы данных (Oracle). Как бы вы моделировали это отношение как таблицы БД и как объекты?доменный дизайн с nhibernate

Я мог бы Project таблицу и ProjectLog таблицы с и имею внешний ключ к первичному ключу Project и сделать «такой же» вещь на уровне объекта есть класс Project и свойство

IEnumerable<LogEntry> LogEntries { get; }

и NHibernate делает все сопоставление. Но как бы мне создать проект ProjectRepository в этом случае? Я мог бы иметь методы

void FillLog(Project projectToFill, DateTime start, DateTime end);

Как я могу сказать NHibernate, что он не должен загрузить LogEntries пока кто-то называет этот метод и как бы я сделать NHibernate для загрузки, специфические временные рамки в пределах этого метода?

Я довольно новичок в ORM, может быть, дизайн не оптимален для NHibernate или вообще? Может быть, мне это нравится?

ответ

1

«правильный» способ загрузки частичные/отфильтрованные/критериев на основе списков под NHibernate является использование запросов. Существует lazy="extra", но он не делает то, что вы хотите.

Как вы уже отметили, это нарушает модель DDD Root Aggregate -> Children. Я боролся с этой проблемой только в абсолютном возрасте, потому что, прежде всего, я ненавидел то, что соответствовало постоянству, касающемуся загрязнения моей модели домена, и я никогда не смог бы получить поверхность API, чтобы выглядеть «правильно». Методы фильтрации в классе владеющих сущностей работают, но далеки от хороших.

В конце концов, я решил расширить свой базовый класс сущности (все мои сущности унаследованы от него, что, как я знаю, в настоящее время немного немодно, но, по крайней мере, позволяет мне делать подобные вещи последовательно) с защищенным методом, называемым Query<T>(), который принимает выражение LINQ, определяющее взаимосвязь, и под капотом в репозитории вызывает LINQ-to-NH и возвращает IQueryable<T>, который затем можно запросить по мере необходимости. Затем я смогу украсить этот вызов под обычным свойством.

Базовый класс делает это:

protected virtual IQueryable<TCollection> Query<TCollection>(Expression<Func<TCollection, bool>> selector) 
     where TCollection : class, IPersistent 
    { 
     return Repository.For<TCollection>().Where(selector); 
    } 

(Здесь я должен отметить, что моя Repository реализация реализует IQueryable<T> непосредственно, а затем делегирует работу вплоть до NH Session.Query<T>())

И facading как это работает :

public virtual IQueryable<Form> Forms 
{ 
    get 
    { 
     return Query<Form>(x => x.Account == this); 
    } 
} 

Это определяет связь списка между учетной записью и формой как обратную к фактической карте (Форма -> Аккаунт).

Для «бесконечных» коллекций - там, где есть потенциально неограниченное количество объектов в наборе - это работает нормально, но это означает, что вы не можете сопоставить отношения непосредственно в NHibernate и, следовательно, не можете использовать свойство непосредственно в NH, только косвенно.

Нам нужна замена общего пакета NHibernate, список и набор реализаций, которые знают, как использовать LINQ-провайдер для непосредственного запроса в списки. Один из них был предложен как патч (см. https://nhibernate.jira.com/browse/NH-2319). Поскольку вы можете видеть, что патч не был закончен или принят, и из того, что я вижу, предложение не переупаковывало это как расширение - Диего Мигельсон - пользователь здесь, на SO, поэтому, возможно, он перезвонит ... У меня есть проверил свой предложенный код как POC, и он работает как рекламируемый, но, очевидно, он не проверен или не гарантирован или не завершен, он может иметь побочные эффекты и без разрешения использовать или публиковать его, вы все равно не сможете его использовать.

До тех пор, пока команда NH не столкнется с написанием/принятием патча, в результате чего это произойдет, нам придется продолжать использовать обходные пути. Здесь NH и DDD имеют противоречивые взгляды на мир.

+0

Итак, ваши объекты имеют зависимость от репозитория (или нескольких хранилищ, если на то пошло)? Это распространено в DDD? – bitbonk

+0

Наверное, нет. Я бы описал наш подход как вдохновленный DDD, но не рабски следя за ним. В нашем сценарии нет никакого огромного недостатка в этом - если бы я был «чистым», тогда я сделал бы это по-другому. Но у кого есть время для чистого? :-) –

+0

Ну, я думаю, по крайней мере, мне нужно, чтобы мой IRepository был введен в мою Entity (желательно ctor-injected). Вы делаете это с окружающим контекстом, который временами бывает немного проблематичным. В чем причина вашего решения? – bitbonk

2

Вместо того, чтобы иметь объект проекта как aggregate root, почему бы не переместить ссылку вокруг и пусть LogEntry имеют Product собственности, а также выступать в качестве aggregate root.

public class LogEntry 
{ 
    public virtual Product Product { get; set; } 
    // ...other properties 
} 

public class Product 
{ 
    // remove the LogEntries property from Product 
    // public virtual IList<LogEntry> LogEntries { get; set; } 
} 

Теперь, так как эти предприятия являются агрегатные корни, вы бы два различных репозиториев: ProductRepository и LogEntryRepository. LogEntryRepository может иметь метод GetByProductAndTime:

IEnumerable<LogEntry> GetByProductAndTime(Project project, DateTime start, DateTime end); 
+0

Кажется странным сделать простую запись в журнале и заполнить корень или даже сущность. У него просто несколько простых пробелов, таких как timestamp, message, logged value, projectID. У него нет дочерних объектов. Он больше похож на объект немого значения. – bitbonk

+1

Возможно, но это должен быть хороший компромисс против борьбы с поведением списка по умолчанию NHibernate. Мне бы хотелось услышать еще несколько мнений об этом. Это интересная тема. –

Смежные вопросы