Мне было предоставлено несколько десятков устаревших операторов SQL, каждая из которых длиной в сотни строк. Каждый SQL сопоставляется с кодом с его собственным уникальным POCO в проекте общих Models
.
Например, SQL Select Name, Birthday From People
имеет эквивалентный POCO в проекте Models
:
public class BirthdayPerson : SqlResultBase {
public string Name { get; set; }
public datetime Birthday { get; set; }
//SqlResultBase abstraction:
public string HardcodedSql { get {
return "Select Name, Birthday From People";
}}
}
В моем DAL у меня есть один общий SQL-бег, чей <T>
представляет POCO для SQL. Поэтому моя бизнес-логика может вызвать GetSqlResult<BirthdayPerson>()
:
public IEnumerable<T> GetSqlResult<T>() where T : SqlResultBase, new() {
return context.Database.SqlQuery<T>((new T()).HardcodedSql);
}
Проблема в том, что моя библиотека Models
используется во всем приложении, и я не хочу, чтобы SQL отображался через приложение в этом свойстве HardcodedSql.
Это архитектура, которую я использую:
Сначала вам нужно отделить свою модель (т.е. POCOs) от SQL, которая фактически принадлежит DAL. Инверсия управления - это правильный способ сделать это. Вместо универсального sql runner лучше регистрировать сопоставления в контейнере IoC из абстрактных репозиториев (например, IRepository<MyPOCO>
) для реализаций, содержащих SQL.
EDIT: Чтобы быть более конкретным, возможно решение:
IRepository<MyPOCO1> => LegacyRepo<MyPOCO1>; IRepository<MyPOCO2> => LegacyRepo<MyPOCO2>; etc
IRepository<MyPOCO1> => LegacyRepo<MyPOCO1>; IRepository<MyPOCO2> => LegacyRepo<MyPOCO2>; etc
IRepository<MyPOCO1> => LegacyRepo<MyPOCO1>; IRepository<MyPOCO2> => LegacyRepo<MyPOCO2>; etc
Кроме того, вы можете регистрировать другие сопоставления из не-устаревших объектов в другие реализации репозитория.Type
(две переменные универсального)?
Я предлагаю, возможно, два возможных способа решения этого вопроса.
Что касается первого метода, я бы предпочел изменить способ доступа к sql и локально локализовать вызов в методе. Таким образом, класс может иметь функцию, называемую public IEnumerable GetFromSql(), которую вы могли бы передать в контексте или создать новую, я не уверен, как вы настроили EF в своем проекте. таким образом, вы никогда публично не выставляете необработанный sql, поскольку вы скорее сделаете его частной переменной или локальной константой, возможно, и просто получите доступ к ней изнутри функции.
В качестве второго варианта, и я на самом деле это сделал, и получилось очень здорово, я переместил все sql в представления и использовал EF для доступа к ним. Таким образом, в моем коде не было никакого загрязнения sql. Увидев, что модели уже существуют, результат вызова представлений будет соответствовать тем типам, которые у вас уже есть.
Простейшим решением было бы сделать HardcodedSql
internal
а не public
чтобы он был видимым только в проекте DAL. Если DAL является отдельным проектом из модели, вы можете использовать InternalsVisibleTo
чтобы выставить его на этот проект. Это предполагает, что вы можете соответствующим образом настроить структуру проекта.