Рекомендации по сопоставлению объектов домена (ORM) с объектами передачи данных (DTO) - PullRequest
12 голосов
/ 03 сентября 2008

Текущая система, над которой я работаю, использует Castle Activerecord для обеспечения ORM (Object Relational Mapping) между объектами Domain и базой данных. Это все хорошо, и в большинстве случаев на самом деле хорошо работает!

Проблема возникает с поддержкой Castle Activerecords для асинхронного выполнения, а точнее, SessionScope, который управляет сеансом, к которому принадлежат объекты. Короче говоря, случается плохое!

Поэтому мы ищем способ легко преобразовать (мыслить автоматически) из объектов Домена (которые знают, что БД существует и заботится) в объект DTO (которые ничего не знают о БД и не заботятся о сессиях, отображая атрибуты или все это ORM).

Есть ли у кого-нибудь предложения по этому поводу? Для начала я ищу базовое сопоставление объекта «один к одному». Объект домена Person будет отображен, чтобы сказать PersonDTO . Я не хочу делать это вручную, так как это пустая трата времени.

Очевидно, что на ум приходит размышление, но я надеюсь, что некоторые лучшие ИТ-знания, распространяющиеся вокруг этого сайта, предложат "круче" .

О, я работаю в C #, объекты ORM, как было сказано ранее, сопоставлены с Castle ActiveRecord.


Пример кода:

По запросу @ ajmastrean я связал с примером, который я (плохо) высмеял вместе. В этом примере есть форма захвата , форма захвата контроллер , домен объекты, activerecord репозиторий и async помощник , Это немного большой (3 МБ), потому что я включил ActiveRecored DLL, необходимые для его запуска. Вам нужно будет создать базу данных с именем ActiveRecordAsync на локальном компьютере или просто изменить файл .config.

Основные детали примера:

Форма захвата

Форма захвата имеет ссылку на контроллер

private CompanyCaptureController MyController { get; set; } 

При инициализации формы она вызывает MyController.Load () закрытое void InitForm () { MyController = новый CompanyCaptureController (это); MyController.Load (); } Это вернется к методу LoadComplete ()

public void LoadCompleted (Company loadCompany)
{
    _context.Post(delegate
    {
         CurrentItem = loadCompany;
         bindingSource.DataSource = CurrentItem;
         bindingSource.ResetCurrentItem();
         //TOTO: This line will thow the exception since the session scope used to fetch loadCompany is now gone.
         grdEmployees.DataSource = loadCompany.Employees;
         }, null);
    }
}

это то место, где "плохие вещи" встречаются, так как мы используем дочерний список Company, который установлен как Ленивая загрузка.

Контроллер

Контроллер имеет метод Load, который был вызван из формы, затем он вызывает помощник Asyc для асинхронного вызова метода LoadCompany, а затем возвращается к методу LoadComplete формы Capture.

public void Load ()
{
    new AsyncListLoad<Company>().BeginLoad(LoadCompany, Form.LoadCompleted);
}

Метод LoadCompany () просто использует Репозиторий, чтобы найти известную компанию.

public Company LoadCompany()
{
    return ActiveRecordRepository<Company>.Find(Setup.company.Identifier);
}

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

Ответы [ 5 ]

9 голосов
/ 04 октября 2008

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

public static T ChangeType<S, T>(this S source) where T : class, new()

В первый раз, когда этот метод (или любая другая перегрузка) выполняется для двух типов, он просматривает свойства каждого типа и решает, какие из них существуют как на основе имени, так и типа. Он берет это «пересечение членов» и использует класс DynamicMethod для эмуляции IL, чтобы скопировать исходный тип в целевой тип, а затем кэширует результирующий делегат в потоковом безопасном статическом словаре.

Как только делегат создан, он непристойно быстр, и я предоставил другие перегрузки для передачи делегату для копирования свойств, которые не соответствуют критериям пересечения:

public static T ChangeType<S, T>(this S source, Action<S, T> additionalOperations) where T : class, new()

... чтобы вы могли сделать это для своего примера Person to PersonDTO:

Person p = new Person( /* set whatever */);
PersonDTO = p.ChangeType<Person, PersonDTO>();

И любые свойства как Person, так и PersonDTO (опять же, имеющие одинаковые имя и тип) будут скопированы с помощью метода, генерируемого во время выполнения, и любые последующие вызовы не будут сгенерированы, но будут повторно использовать тот же код, сгенерированный для этих типов в указанном порядке (т. е. копирование PersonDTO в Person также повлечет за собой попадание кода).

Слишком много кода для публикации, но если вам интересно, я приложу усилия, чтобы загрузить образец в SkyDrive и опубликовать ссылку здесь.

Richard

4 голосов
/ 15 июня 2010

используйте ValueInjecter , с его помощью вы можете сопоставить что угодно с чем угодно, например

  • объект <-> объект
  • object <-> Form / WebForm
  • DataReader -> object

и имеет классные функции, такие как: сплющивание и отстегивание

загрузка содержит много образцов

2 голосов
/ 23 апреля 2010

Вы должны использовать автомат, о котором я писал здесь:

http://januszstabik.blogspot.com/2010/04/automatically-map-your-heavyweight-orm.html#links

До тех пор, пока свойства будут называться одинаково на обоих ваших объектах, автоматический обработчик будет обрабатывать их.

0 голосов
/ 22 ноября 2008

На самом деле я сейчас совсем запутался. Потому что вы говорите: «Поэтому мы ищем способ легко преобразовать (мыслить автоматически) из объектов Домена (которые знают, что БД существует и заботятся) в объект DTO (которые ничего не знают о БД и не заботятся о сессиях» , сопоставление атрибутов или всего прочего ORM). "

  1. Доменные объекты знают и заботятся о БД? Не в этом ли смысл доменных объектов содержать ТОЛЬКО бизнес-логику и полностью не знать о БД и ORM? .... У вас должны быть эти объекты? Вам просто нужно ИСПРАВИТЬ их, если они содержат все это ... поэтому я немного запутался, как DTO входит в картину

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

0 голосов
/ 04 октября 2008

Приношу свои извинения за то, что на самом деле не привожу здесь подробности, но основной ОО-подход состоял бы в том, чтобы сделать DTO членом класса ActiveRecord и позволить ActiveRecord делегировать методы доступа и мутаторы DTO. Вы можете использовать инструменты генерации кода или рефакторинга, чтобы довольно быстро создавать классы DTO из классов AcitveRecord.

...