Предложения о том, как сопоставить объекты домена (ORM) с объектами передачи данных (DTO)

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

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

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

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

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

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


Пример кода:

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

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

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

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

private CompanyCaptureController MyController { get; set; } 

При инициализации формы вызывается MyController.Load() private void InitForm () { MyController = new CompanyCaptureController(this); МойКонтроллер.Загрузить(); } Это вернет метод 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.


person FryHard    schedule 03.09.2008    source источник


Ответы (5)


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

Ричард

person ZeroBugBounce    schedule 04.10.2008

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

  • объект ‹-> объект
  • объект ‹-> Форма/Веб-форма
  • DataReader -> объект

и у него есть интересные функции, такие как: сглаживание и распрямление

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

person Omu    schedule 15.06.2010

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

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

Пока свойства названы одинаково на обоих ваших объектах, автосопоставление будет обрабатывать это.

person januszstabik    schedule 22.04.2010
comment
Мертвая ссылка сейчас. Ура, линкрот. - person Bobson; 18.06.2012

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

person MattMcKnight    schedule 04.10.2008

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

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

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

person Paul Kapustin    schedule 21.11.2008