Сохранение AutoMapper ProjectTo () DRY, когда свойства имеют одинаковый код - PullRequest
0 голосов
/ 01 октября 2018

Я хочу использовать запрашиваемые расширения AutoMapper (.ProjectTo), но я не могу понять, как это сделать, не копируя код во многие мои свойства объектов базы данных и не дублируя его в проекции.Вот пример, который переопределяет ToString и имеет настраиваемое свойство:

class Claim {
  public int Id { get; set; }
  public int TypeId { get; set; }
  public ClaimType Type { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string Name
    => $"{FirstName} {LastName}";
}

class ClaimType {
  public int Id { get; set; }
  public string Value { get; set; }
  public string Abbrev { get; set; }
  public override string ToString()
    => Value + (Abbrev != null ? $" ({Abbrev})" : "");
}

class ClaimViewModel {
  public int Id { get; set; }
  public string Type { get; set; }
  public string Name { get; set; }
}

Теперь предположим, что у меня есть две вышеупомянутые модели базы данных и модель представления. Я хочу проецировать Claim на ClaimViewModel в запросе.Единственный способ, которым я знаю, как это сделать, таков:

CreateMap<Claim, ClaimViewModel>()
  .ForMember(c => c.ClaimType, x => x.MapFrom(c => c.ClaimType.Value + (c.ClaimType.Abbrev != null ? $" ({c.ClaimType.Abbrev})" : "")))
  .ForMember(c => c.Name, x => x.MapFrom(c => $"{c.FirstName} {c.LastName}"));

Очевидно, что это дублирует код свойства Name и метода ClaimType.ToString.Существуют ли какие-либо установленные шаблоны для решения этой проблемы и сохранения кода СУХОЙ?У нас есть много пользовательских свойств и переопределений ToString в наших моделях.Я обнаружил, что могу сделать следующее для свойства Name ... сначала в классе Claim:

public static readonly Expression<Func<Claim, string>> NameExpr = (c) => $"{c.FirstName} {c.LastName}";
public string Name => NameExpr(this);

А затем в сопоставлении сделать это:

.ForMember(c => c.Name, x => x.MapFrom(Claim.NameExpr));

Thisкажется вполне подходящим для этого очень простого случая, но он не работает для ситуаций со ссылками на внешние ключи, таких как метод ClaimType.ToString.В этом случае я мог бы поместить выражение в Claim и сослаться на него в сопоставлении Claim, но в тот момент, когда мне нужно было проецировать ClaimType в ClaimTypeViewModel, мне пришлось бы продублировать код.Или, если бы существовала другая модель базы данных, ссылающаяся на модель ClaimType, у меня возникла бы та же проблема.

Если ответ имеет значение, ORM будет EF Core @ 2.1.3.

РЕДАКТИРОВАТЬ: Я не понял этого, когда писал этот вопрос, но приведенное выше отображение будет работать без конфигурации ForMember, но я заметил в SQL Profiler, что запрос будет откатывать каждый столбец в Claim и ClaimTypeмодели, а не только необходимые столбцы.Это хорошо, но мне действительно нужен бонус производительности ProjectTo только для того, чтобы вытащить нужные столбцы.

1 Ответ

0 голосов
/ 09 октября 2018

@ LucianBargaoanu предоставил правильный ключ к отличному, работающему решению. AutoMapper.EF6 предоставляет несколько простых оболочек для этого;на самом деле они представляют собой пакет DelegateDecompiler , который выполняет настоящую работу.Окончательное решение выглядит следующим образом:

Во-первых, сделайте ссылку на DelegateDecompiler, добавив пакет NuGet в ваш проект (ы).

Во-вторых, добавьте ComputedAttribute к любым вычисленным свойствам или функциям намодели, которые вы ожидаете, что EFCore сможет правильно обрабатывать превращение в SQL, например:

class Claim {
  [Computed]
  public string Name
    => $"{FirstName} {LastName}";
}

class ClaimType {
  [Computed]
  public override string ToString()
    => Value + (Abbrev != null ? $" ({Abbrev})" : "");
}

Наконец, любое место, которое вы хотите вызвать ProjectTo, также добавляет Decompile() (или DecompileAsync()) к нему.например,

var myClaimViewModels = Db.Claims.ProjectTo<ClaimViewModel>(Mapper.ConfigurationProvider).Decompile().ToList();

Я убедился, что приведенный выше код работает хорошо, даже используя переопределенный метод ToString, помеченный как Computed.Я проверил SQL Server Profiler, чтобы убедиться, что запрос извлекает только необходимые столбцы, и, к счастью, это так.

Для справки, библиотека AutoMapper.EF6 действительно имеет только единственный исходный файл и его можно легко скопировать и вставить в ваш собственный источник, ориентируясь на EF Core вместо EF 6.

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