провайдеры F # типа против C# интерфейсов + Entity Framework

Вопрос задан: 1 год назад Последняя активность: 7 месяцев назад
up 12 down

Вопрос очень технический, и она сидит глубоко между F #/C# различий. Вполне вероятно, что я мог бы что-то пропустил. Если вы нашли концептуальную ошибку, пожалуйста, комментарий и я буду обновлять этот вопрос.

Давайте начнем с C# мира. Предположим, что у меня есть простой бизнес-объект, назовем его Person (Но, пожалуйста, имейте в виду, что существует более 100 объектов гораздо сложнее, чем в области бизнеса, что мы работаем с):

public class Person : IPerson
{
    public int PersonId { get; set; }
    public string Name { get; set; }
    public string LastName { get; set; }
}

и я использую DI/МОК и так, что я никогда не пропускать Person около. Скорее всего, я бы всегда использовать интерфейс (упомянутый выше), назовем его IPerson:

public interface IPerson
{
    int PersonId { get; set; }
    string Name { get; set; }
    string LastName { get; set; }
}

Требование бизнеса является то, что человек может быть сериализовать в/десериализации из базы данных. Допустим, я выбираю использовать Entity Framework для этого, но фактическая реализация кажется не имеет отношения к вопросу. На данный момент у меня есть возможность ввести «базу данных», связанный класс (ы), например, EFPerson:

public class EFPerson : IPerson
{
    public int PersonId { get; set; }
    public string Name { get; set; }
    public string LastName { get; set; }
}

наряду с соответствующими атрибутами и кодом базы данных, связанными, которые я пропущу для краткости, а затем использовать отражение для копирования свойств IPerson интерфейс между Person а также EFPerson ИЛИ просто использовать EFPerson (Принят в качестве IPerson) Непосредственно или сделать что-то другое. Это справедливо не имеет значения, так как потребители всегда будут видеть IPerson и поэтому реализация может быть изменена в любое время без потребителей ничего не зная о нем.

Если мне нужно добавить свойство, то я бы обновить интерфейс IPerson первый (скажем, добавить недвижимость DateTime DateOfBirth { get; set; }), А затем компилятор скажет мне, что исправить. Тем не менее, если я удалить свойство из интерфейса (скажем, что я больше не нужен LastName), То компилятор не поможет мне. Тем не менее, я могу написать тест Reflection на основе, которая гарантировала бы, что свойства IPerson, Person, EFPerson, и т.д. идентичны. Это на самом деле не нужно, но это может быть сделано, и тогда он будет работать как волшебство (да, у нас есть такие тесты, и они работают как волшебство).

Теперь давайте перейдем к F # миру. Здесь мы имеем поставщик типа, которые полностью устраняют необходимость создания объектов базы данных в коде: они создаются автоматически поставщиками типа!

Здорово! Но это?

Во-первых, кто-то должен создать/обновить объекты базы данных и, если есть более чем один разработчик занимается, то естественно, что база данных может и будет повышен/понижен в различных отраслях. До сих пор, из моего опыта, это крайняя боль на шее, когда поставщики F # типа участвуют.д.же если C# EF Code First используется для обработки миграции, некоторые «обширные шаман танцы» требуется, чтобы провайдеры F # типа «счастливым».

Во-вторых, все неизменны в F # мире по умолчанию (если не сделать его изменчивый), так что мы явно не хотим передать изменяемые объекты базы данных вверх по течению. Это означает, что когда мы загружаем изменяемую строку из базы данных, мы хотим, чтобы превратить его в «родной» F # непреложного структуры как можно скорее таким образом, чтобы работать только с чистыми функциями вверх по течению. В конце концов, используя чистые функции уменьшает количество необходимых тестов в, я думаю, 5 - 50 раз, в зависимости от области.

Давайте вернемся к нашему Person. Я пропущу все возможные переназначения на текущий момент (целое число баз данных, например в случае F # DU и аналогичный материал). Итак, наш F # Person будет выглядеть так:

type Person =
    {
        personId : int
        name : string
        lastName : string
    }

Так что, если «завтра» мне нужно добавить dateOfBirth : DateTime к этому типу, то компилятор скажет мне обо всех местах, где это должно быть исправлено. Это здорово, потому что C# компилятор не скажет мне, где нужно добавить, что дата рождения,... за исключением базы данных. F # компилятор не скажет мне, что я должен пойти и добавить столбец базы данных в таблице Person. Однако, в C#, так как я бы обновить интерфейс первым, компилятор покажет мне, какие объекты должны быть зафиксированы, в том числе базы данных одного (ов).

Видимо, я хочу лучшее из обоих миров в F #. И хотя это может быть достигнуто с помощью интерфейсов, то он просто не чувствует F # пути. В конце концов, аналог DI/МОК делается очень по-разному в F # и обычно достигается путем передачи функций, а не интерфейсов.

Итак, вот два вопроса.

  1. Как я могу легко управлять базой данных вверх/вниз миграции в F # мире? И, чтобы начать с, что такое правильный способ действительно сделать миграции базы данных в F # мире, когда многие разработчики занимаются?

  2. Что такое F # способ достижения «лучший из C# мира», как описано выше: когда я обновляю F # тип Person а затем исправить все места, где мне нужно, чтобы добавить/удалить свойство записи, что будет наиболее подходящим F # способ «сбоя» либо во время компиляции, или, по крайней мере, на время тестирования, когда я не обновил базу данных, чтобы соответствовать бизнесу объекты)?

1 ответ

Возможно, для Вашего проекта будут необходимы бесплатные векторные карты. На нашем сайте представлены карты для всех стран.

Реклама

up 1 down accepted

Как я могу легко управлять базой данных вверх/вниз миграции в F # мире?   И, чтобы начать с, что такое правильный способ действительно сделать базу данных   Миграции в F # мире, когда многие разработчики занимаются?

Наиболее естественный способ управления Db миграции заключается в использовании инструментов произрастающих дб т.е. простой SQL. В нашей команде мы используем dbup пакет для каждого решения мы создаем небольшой консольный проект засучить DB миграцию в разработчике и во время развертывания. Потребительские приложения находятся в F # (провайдеров типа) и C# (EF), иногда с одной и той же базе данных. Работает как шарм.

Вы упомянули EF Code First. F # провайдеры SQL все по своей сути «Db First», потому что они создают типы на основе внешнего источника данных (базы данных), а не наоборот. Я не думаю, что смешение двух подходов является хорошей идеей. На самом деле я бы не рекомендовал EF Code First любой управлять миграциями: обычный SQL проще, не требует «обширного шаманского танца», гораздо более гибкого и понимали гораздо больше людей. Если вы плохо знакомы с ручной SQL сценариев и рассмотрим EF Code First только для автоматической генерации миграции сценария, то даже MS SQL Server Management Studio разработчик может создавать миграционные сценарии для вас

Что такое F # способ достижения «лучший из C# мира», как описано   выше: когда я обновляю F # тип Person, а затем исправить все места, где я   нужно добавить/удалить свойство записи, что было бы наиболее   соответствующий F # способ «сбой» либо во время компиляции, или по крайней мере   время тестирования, когда я не обновил базу данных, чтобы соответствовать бизнес   объекты)?

Мой рецепт выглядит следующим образом:

  • Не использовать интерфейсы. как ты сказал :)

интерфейсы, он просто не чувствует F # способа

  • Не позволяйте автогенерируемые типа от поставщика типа просачиваться наружу тонкий слой дб доступа. Они не являются бизнес-объекты, и ни EF объекты не являются собственно говоря.
  • Вместо того, чтобы объявить F # запись и/или дискриминационные союзы как ваши объекты домена. Модель их как угодно и не скован дб схема.
  • В дб уровня доступа, карта с автоматически сгенерированных дб типов для вашего домена F типов #. Каждое использование типов генерироваться автоматически по типу поставщика начинается и заканчивается здесь. Да, это означает, что вы должны написать сопоставления вручную и ввести человеческий фактор здесь, например, вы можете случайно карту ПгвЬЫата на LastName. На практике это крошечные накладные расходы и преимущество развязки перевешивает его величиной.
  • Как убедиться, что вы не забыли карту некоторого свойства? Это невозможно, F # компилятор будет выдавать ошибку, если запись не полностью инициализирован.
  • Как добавить новое свойство и не забудьте инициализировать его? Начните с F # кодом: добавить новое свойство в области записи/записи, F # компилятор будет направлять вас все записи конкретизации (как правило, только один) и заставить вас инициализировать его с чем-то (вы должны добавить миграционный скрипт/обновить схему базы данных, соответственно, ).
  • Как удалить свойство и не забудьте очистить все до дб схемы. Начните с другого конца: удалить столбец из базы данных. Все отображения между типами поставщиков типа и областями F # записями сломаются и выделить свойства, которые стали лишними (что более важно, это заставит вас дважды проверить, что они действительно лишние и пересмотреть свое решение).
  • На самом деле в некоторых случаях вы можете захотеть сохранить столбец базы данных (например, для исторических целей/аудита) и только удалить свойство из F # код. Это только один (и довольно редко) из множества сценариев, когда это удобно, чтобы иметь модель предметной области отсоединяется от дб схемы.

Короче говоря

  • миграции через простой SQL
  • типы доменов вручную объявлены F # записи
  • ручное отображение провайдеров типа для F # типов доменов

Даже Шортер

Палка с единой ответственностью Принципом и пользоваться преимуществами.

Ошибка 505

Что-то пошло не так

Попробуйте воспользоваться поиском