Полная анемия - где я могу переместить эти данные из моей модели?

1

Мне было предоставлено несколько десятков устаревших операторов 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.

Это архитектура, которую я использую:

Изображение 174551

  • 0
    разве это не поможет, если вы скорее создадите функцию в классе и вернете результат из функции, чтобы вы могли поместить необработанный sql в приватную переменную и не раскрывать ее везде?
  • 0
    Это звучит почти замечательно. Насколько я понимаю, что вы предлагаете, я почти уверен, что веб-интерфейс все еще может просто вызвать метод и прочитать предоставленный SQL.
Показать ещё 2 комментария
Теги:
anemic-domain-model

3 ответа

1
Лучший ответ

Сначала вам нужно отделить свою модель (т.е. POCOs) от SQL, которая фактически принадлежит DAL. Инверсия управления - это правильный способ сделать это. Вместо универсального sql runner лучше регистрировать сопоставления в контейнере IoC из абстрактных репозиториев (например, IRepository<MyPOCO>) для реализаций, содержащих SQL.

EDIT: Чтобы быть более конкретным, возможно решение:

  • Поместите все SQL файлы в отдельный файл внутри DAL, например, в набор встроенных файлов ресурсов с условным обозначением имен, например Legacy- {0}.sql, где {0} - имя POCO.
  • Создайте общую реализацию устаревшего репозитория, который использует имя POCO в качестве ключа и выбирает соответствующий файл Legacy- {0}.sql из набора ресурсов. Обратите внимание, что могут быть и другие реализации, которые используют другие методы доступа к данным, такие как ORM.
  • В корневом каталоге композиции явно отображаются все сопоставления из устаревших POCOs в устаревшую реализацию: 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 Кроме того, вы можете регистрировать другие сопоставления из не-устаревших объектов в другие реализации репозитория.
  • 0
    Кроме того, вы можете переместить их в представления SQL, как предлагает Луи Льюис. Тогда реализация репозитория будет ссылаться на представление, а не содержать необработанный оператор SQL
  • 0
    Вы правы в том, что SQL не принадлежит POCO и должен быть в DAL. Это главный вопрос. В настоящее время мой корень композиции находится либо в локальном app_start, либо в сервисе app_start, и композиция использует внедрение-конструктор для обеспечения внедрения зависимостей на всех уровнях. Что может быть хорошим ответом, так это некоторая проработка той части, в которой вы говорите «реализациям, содержащим SQL». Вы хотите избавиться от универсального и создать дублирующую функцию для каждого типа, кроме выражения SQL и Type (две переменные универсального)?
Показать ещё 6 комментариев
1

Я предлагаю, возможно, два возможных способа решения этого вопроса.

Что касается первого метода, я бы предпочел изменить способ доступа к sql и локально локализовать вызов в методе. Таким образом, класс может иметь функцию, называемую public IEnumerable GetFromSql(), которую вы могли бы передать в контексте или создать новую, я не уверен, как вы настроили EF в своем проекте. таким образом, вы никогда публично не выставляете необработанный sql, поскольку вы скорее сделаете его частной переменной или локальной константой, возможно, и просто получите доступ к ней изнутри функции.

В качестве второго варианта, и я на самом деле это сделал, и получилось очень здорово, я переместил все sql в представления и использовал EF для доступа к ним. Таким образом, в моем коде не было никакого загрязнения sql. Увидев, что модели уже существуют, результат вызова представлений будет соответствовать тем типам, которые у вас уже есть.

  • 0
    Было бы здорово использовать Views, но компания дала мне SQL для размещения в коде. Это отличное предложение, но они отказываются использовать Views, Stored Procs или что-либо, кроме Trigger в своей БД. Спасибо за это предложение, хотя.
1

Простейшим решением было бы сделать HardcodedSql internal а не public чтобы он был видимым только в проекте DAL. Если DAL является отдельным проектом из модели, вы можете использовать InternalsVisibleTo чтобы выставить его на этот проект. Это предполагает, что вы можете соответствующим образом настроить структуру проекта.

  • 0
    Я явно не правильно прочитал это сначала. Я собираюсь заглянуть в InternalsVisibleTo очень быстро и вернуться к этому, это звучит здорово.
  • 0
    Ах да, я помню это сейчас. Я думаю, что я отказался когда-либо знать о InternalsVisibleTo, потому что, на мой взгляд, это будет означать запах кода. В случае моей текущей ситуации, конечно, есть запах кода, и мне это не нравится. Так что, хотя InternalsVisibleTo может помочь, я очень надеюсь на решение избавиться от вони. Также возможно, что это неизбежно для требований, которые мне дали, но, надеюсь, это не так, и я просто что-то упускаю. Здесь может быть в порядке РЕЛИЗ ТВЕРДЫХ, и предложения по этому пути были бы идеальным ответом.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню