Объекты переноса данных и IQueryable: сборка и разборка объекты переноса данных


Я работаю над проектом, который использует шаблон ассемблера для сборки объектов LinqToEntity в объекты передачи данных на уровне сервиса, которые затем передаются на уровень клиента для использования. Подход состоял в том, чтобы перевести объекты entitie в упрощенные плоские объекты, которые предоставляют информацию, специфичную для вызова службы.

Напр.

// Original Entity looks something like this
public class PersonEntity
{
   public int Id { get; set; }
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public int MotherId { get; set; }  
   public PersonEntity Mother { get; set; }
   // lots of other properties
}

// Flattened DTO
public class PersonSummaryInfo
{
  public int Id { get; set; }
  public string FullName { get; set; }
  public string MothersFullName { get; set; }
}

В этом примере ассемблер создаст PersonSummaryInfo, построив часть FullNames процесс.

Теперь я сталкиваюсь с проблемой с некоторым контролем третьей стороны (Telerik ASP.NET MVC GridControl), где элемент управления настраивается на фильтрацию (с помощью IQueryable) на основе свойств модели. Там идея, кажется, заключается в том, что у вас есть одноуровневый дизайн и выкачивать объекты базы данных непосредственно в представление, которое я не могу вынести.

Пытаясь включить его в мою логику, GridControl привязывается к моему DTO вместо сущности, которая все хороша, пока она не попытается что-нибудь отсортировать. Я толкнул все из IQueryable вещи в мою службу в очень общем fasion, чтобы сделать его reponsible для этого. Сортировка попытки сортировки, скажем MothersFullName на ДТО (его поведение, чтобы пройти "MothersFullName" как строку в ваш сортировка логика), это довести до моего сервиса, которые посредством отражения попытки сортировки лицам, осуществляющим использование интерфейса IQueryable отложенной загрузки, но, конечно, когда запрос выполняется, возникает исключение, как "MothersFullName" - это не свойство оригинала Сущность.

Есть ли хорошая стратегия, которая справляется с такого рода реализацией? Является ли хорошей практикой эффективно "разбирать" DTO обратно в его ORM-сущность, как только он возвращается на уровень обслуживания приложения? Или лучше передать более богатые объекты, которые имеют больше знаний о том, что они собой представляют (например, как сортировать полное имя с помощью имени и фамилии)?

Что является ключом к моим требованиям:

  • используют необычный Телерик контроль, потому что им это нравится
  • ленивый загрузка результатов на уровне сервиса (т. е. не возвращайте 2 миллиона записей и просто покажите 10)
  • Поддержка фильтрации, подкачки и т.д.
  • звуковая архитектурная реализация
3 3

3 ответа:

У вас есть несколько вариантов перед собой. Во-первых, верно, что он может быть привязан к IQueryable, потому что это самый быстрый (и самый распространенный) способ сделать это, с точки зрения времени разработки, конечно.

В вашем случае (полномасштабный сервисный слой поверх ORM) ситуация немного отличается. Я бы лично предложил вам копнуть немного и предоставитьпользовательские привязки к вашей сетке. Вы получаете объект GridCommand, который можно запросить для сортировки и фильтрация и использование ее для запроса данных на уровне сервиса. Это хорошее место, чтобы упомянуть простой способ решить проблему, с которой вы столкнулись (это то, что ваши выражения основаны на свойствах DTO). Вы можете попробовать использоватьDynamic Linq . Просто постройте свои строковые запросы из выражений и передайте их в DAL.

На самом деле, это рекомендуемая лучшая практика другого продукта Telerik-OpenAccess ORM. Пакет OpenAccess SDK содержит пара примеров (особенно WCF Plain Services один), которые используют аналогичную архитектуру для вашего. Продукт также предоставляет инструмент генерации кода , который обеспечивает весь уровень сервиса.

Вы используете RadGrid только для его функции сортировки из коробки? Я столкнулся с этой же проблемой и закончил тем, что просто использовал RadListView и подключил к нему пейджер/сортировку. Используя шаблон, вы можете точно указать ему, что нужно сортировать с помощью свойства SortExpession. Тогда речь как раз о стрельбе по нужному событию. Вот мой обработчик событий, вы можете установить все, что вы можете получить ваши руки, чтобы запустить его. Я не уверен, что это решение, но надеюсь, что оно поможет вам найти его:

protected void SortSearchTickets(object sender, RadComboBoxSelectedIndexChangedEventArgs e)
    {
        var selectedValue = e.Value;
        lsvSearchResults.SortExpressions.Clear();
        var sortExp = new RadListViewSortExpression();

        switch (selectedValue)
        {
            case "ID":
                sortExp.FieldName = "TicketID";
                break;
            case "TicketType":
                sortExp.FieldName = "TypeDescription";
                break;
            case "Subject":
                sortExp.FieldName = "Subject";
                break;
            case "Status":
                sortExp.FieldName = "Status.Key";
                break;
            case "DueDateDesc":
                sortExp.FieldName = "DueDate";
                sortExp.SortOrder = RadListViewSortOrder.Descending;
                break;
            case "DueDateAsc":
                sortExp.FieldName = "DueDate";
                sortExp.SortOrder = RadListViewSortOrder.Ascending;
                break;
            case "Assigned To":
                sortExp.FieldName = "AssignedTo.Key";
                break;
            case "Assigned By":
                sortExp.FieldName = "AssignedBy.Key";
                break;
            default:
                break;
        }
        lsvSearchResults.SortExpressions.AddSortExpression(sortExp);
        lsvSearchResults.Rebind();
    }

Пошел с этим решением.

Создание SQL-представлений, содержащих столбцы таблицы. Затем заставил объекты передачи данных использовать свойства, которые точно соответствуют свойствам представления. Не самый чистый и надежный способ добиться этого, но, по крайней мере, он позволяет получить ссылки на мои данные из моих проектов, которые в этом не нуждаются.

Не использовал динамический linq, вместо этого сохранил свой общий подход и использовал отражение, чтобы получить имена столбцов для сопоставления. Не пошли на открытый доступ Телерика только потому, что мы уже есть целый уровень сервиса реализован, но это звучит как хорошее решение.

Это все еще IQueryable, поэтому эффективно он работает очень хорошо (просто полагается на разработчиков, чтобы гарантировать, что GridViews соответствуют GridViewModels, свойство для свойства).