Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
CodeFirst… Поэтому мне нужны картинки. Компактные, наглядные, удобные. Причем модель должна быть не на одной картинке, а на нескольких, по-частям, выбранным как-то предметно. Ну, и далее, с картинок что-то как-то должно генерироваться, не буду же я писать однотипный код сотнями раз, да ещё и не делать при этом ошибок.
Ответ очевиден. Потому что это именно «визуализация», а никак не «проектирование».
Для примера, я хочу прямо с диаграммы указать название таблицы в базе для хранения сущностей определённого класса. Или указать имя поля. [...] Опять же, нарисовал, нажал кнопку, — получил классы и БД. Если нужно получить изменения: нажал кнопку, получил DDL для изменения структуры базы и опять же код классов соответственно изменился. А в код лезть в каких-то очень исключительных случаях.
визуальные редакторы могут и всякого наворотить, и комментарии после их воздействия могут неожиданно исчезать, и прочие подобные неожиданности— так это от инструментария зависит, тут под одну гребёнку не сильно погребёшь.
Помните, что люди архитектуры решают проблемы, которые, как они думают, они могут решить, а не те проблемы, которые полезно решать
return Entities
.Include("Act")
.Include("Act.Zags")
.Include("PeopleBorn")
.Include("PeopleBorn.PeopleInfo")
.Include("PeopleBorn.PeopleInfo.Passport")
.Include("PeopleBorn.PeopleInfo.Passport.OrganizationInfo")
.Include("PeopleBorn.Locations")
.Include("PeopleBorn.Locations.Location")
.Include("Father")
.Include("Mother")
.Include("Father.PeopleInfo")
.Include("Father.PeopleInfo.Passport")
.Include("Father.PeopleInfo.Passport.OrganizationInfo")
.Include("Mother.PeopleInfo")
.Include("Mother.PeopleInfo.Passport")
.Include("Mother.PeopleInfo.Passport.OrganizationInfo")
.Include("Father.Locations")
.Include("Mother.Locations")
.Include("Father.Locations.Location")
.Include("Mother.Locations.Location")
.Include("Declarant")
.Include("Declarant.PeopleInfo")
.Include("Declarant.PeopleInfo.Passport")
.Include("Declarant.PeopleInfo.Passport.OrganizationInfo")
.Include("Declarant.Locations")
.Include("Declarant.Locations.Location")
Там и диаграммы классов есть и много ещё чего интересного, напишу, если дадут.
В руки попадают проекты, у которых, например, code-first и х.з. как настроено отображение в базу.
если бы был предложен инструмент, позволяющий это быстро сделать, не было бы ему так лениво написать по-человечески
Когда счёт идёт на сотни, вы этого уже не можете.
НО вот ведь беда: если мы просто пишем Include, читаются ВСЕ свойства как своей, так и связанных сущностей.
Раз он доступен сразу из коробки с Microsoft Visual Studio…
Кроме очевидных архитектурных и программистских глупостей, [...] были и проблемы, связанные только с Entity Framework.
CodeFirst и DBFirst не предлагать.
Мой аргумент прост: пока у вас 5-10-15 сущностей, вы можете держать структуру системы в голове. [...] Когда счёт идёт на сотни, вы этого уже не можете. [...] Поэтому мне нужны картинки. Компактные, наглядные, удобные. Причем модель должна быть не на одной картинке, а на нескольких, по-частям, выбранным как-то предметно.
Ну, и далее, с картинок что-то как-то должно генерироваться, не буду же я писать однотипный код сотнями раз, да ещё и не делать при этом ошибок.
Надо вручную инициализировать первичные ключи.
Для связывания сущностей надо не только установить navigation property, но и проставить правильно внешний ключ,
Required
не работает ожидаемым образом, но это уже другой разговор.С одной стороны, почему бы и нет, особенно, если ключ целочисленный, но с другой стороны, пока я не выполню запрос по сохранению, я не имею возможности понять, какой будет ключ, и использовать его дальше.
Прицепление или добавление объектов в контекст производится только вызовом метода у коллекции соответствующего типа. Причем используются разные методы: для добавления — Add, а для прицепления существующего — Attach. Что так «удобно»?
Add
— это обычное добавление из CRUD, а Attach
— это операция из detached entity management. В норме вы используете либо всегда одно, либо всегда другое, но не оба сразу. Да, и именно поэтому после Attach
нужно проставлять статусы.Может в вопросе что, куда и как добавить, Entity Framework совместно с .Net как-нибудь без меня станут разбираться, какого типа эта сущность и что с ней произошло?
T Add<T>(this DbContext dbContext, T entity) { return dbContext.Set<T>().Add(entity);}
Зачем существует контекст?
Или, например, что будет, если попробовать связать объекты, взятые из разных контекстов? То-то, наверное, будет весело.
Что-то многовато телодвижений для такой простой задачи, как конструирование и связывание сущностей друг с другом.
dbContext.Set<Books>().Add(new Book{Title = "EF", AuthorId = 15, Tags = new []{new Tag("programming"), new Tag("tutorial")}});
dbContext.SaveChanges();
Что тут неудобно: Неужели так будем писать под каждую выборку? Это продуктивно?
И потом: цель-то наша не читать, а с сущностями дальше РАБОТАТЬ, т.е. писать логику, которая, в результате приводит к изменению значений полей сущностей.
С какой Visual Studio доступен EF 6+?
Диаграммы классов решают ваши проблемы.
А что за однотипный код вы пишете сотнями раз, и откуда у вас возьмутся корректные картинки для его генерации?
Надо вручную инициализировать первичные ключи.
Нет, не надо. Просто проставьте их как создаваемые на стороне БД.
А, так вам внезапно надо знать, какой ключ будет у объекта до его сохранения? Тогда инициализируйте его сами, он же вам нужен. Да, еще у объектов есть конструкторы.
Да, это продуктивно. Особенно это продуктивно в сочетании с соответствующими инструментами навроде мапперов и контролов.
Да, так удобно, потому что это операции от совершенно разных действий. Add — это обычное добавление из CRUD, а Attach — это операция из detached entity management. В норме вы используете либо всегда одно, либо всегда другое, но не оба сразу. Да, и именно поэтому после Attach нужно проставлять статусы.
Нет, понятно, что EF — не панацея. Но это удобный ORM с LINQ-интерфейсом, активно растущий и потихоньку избавляющийся от своих болячек. Основная-то масса описанных проблем все равно проистекает из самой концепции ORM (aka OR impedance mismatch), а не из реализации в EF.
Надо вручную инициализировать первичные ключи.
Представьте себе, да, надо знать заранее.
ORM должен позволять настроить всё очень тонко и очень детально.
Так Вы разберитесь, Вы за красных или за белых?
CodeFirst позволяет настроить все очень тонко и очень детально. Но Вы в упор отказываетесь это принять. Только в этом Ваша проблема.
Приведите мне пример, как настроить следующее: вот мне надо, чтобы когда идёт update запрос на обновление числового поля в БД, ORM не просто тупо подставил значение как константу (x = значение), а выражением, как разницу между значением, которое было при зачитывании и при обновлении (как x = x + РазницаСтарогоИНовогоЗначений).
Есть объект в базе, у которого Счет.Сумма=100.
1. Два процесса подняли этот объект одновременно (ну, почти одновременно).
2. Затем первый сказал что Счет.Сумма нужно увеличить на 100.
3. Второй сказал что Счет.Сумма нужно увеличить ещё 100.
4. В базе Счет.Сумма = 300 (должно быть).
UPDATE Accounts
SET Amount = 200
WHERE Id = @id AND Amount = @prevAmount
UPDATE Accounts
SET Amount = 200, RowVersion = @newVersion
WHERE Id = @id AND RowVersion = @prevVersion
Но ведь вы согласитесь со мной, что такой способ создаёт бОльшую нагрузку на СУБД, нежели просто использовать относительные значения?
Мне молча нужно получить 300 в этом поле этой записи в БД и всё.
А я попользуюсь более простым средством: ORM просто вычтет или прибавит, если я скажу, что это значение надо учитывать как относительное.
… а потом однажды он чуть-чуть ошибется в том, какое значение когда было прочитано, и все, прощайте деньги у кого-то на счету.
Я к тому, что не хочу разбираться на уровне приложения с конкуренцией. С т.з. повышения конкуренции, лучше вообще отдать этот вопрос СУБД.
Одиночный апдейт решает очень ограниченную задачу «прибавить N», но задача внезапно может вырасти до «прибавить N, если ...». Да и вообще бизнес-логика имеет свойство меняться и разрастаться.
У чела(по этой ссылке на stackoverflow) проблема была в том, что у него в where field = val было поле не являющимся уникальным индексом.
Но если речь о деньгах, то как мне кажется целостность операции более приоритетна чем быстродействие.
Хотя с другой стороны странно, что такой, как мне кажется, достаточно востребованный сценарий(лочить строчку) не поддерживается в EF.
И? Проблема написать where?а также пару джоинов, и вообще перенести всю бизнес-логику на DAL слой. Да, это проблема. У автора впрочем тоже эта проблема есть. Его беспокоит необходимость написать 300 мапперов, а то что все части программы срослись в одно целое и их нельзя будет модифицировать не поломав что-то другое это норм.
В текущей задаче сумма счета не является уникальным индексом.в текущей задаче ничего не сказано о том, как именно селектится строчка, в которую надо записать x=x+n. Сомнительное удовольствие искать строчку по значению денег, а не по первичному ключу.
Какой именно? Массовый апдейт? Есть в расширении.я в скобках написал, какой именно. Лочить строчку, и вообще накладывать на запрос атрибуты подобные WITH (updlock). Когда операции исполняются на разных хостах, синхронизироваться на базе приходится, у нас в проекте как раз и использовался для этого оракловский select for update в транзакции.
Я буду решать такую задачу так:
(как x = x + РазницаСтарогоИНовогоЗначений)
Вы прекрасно понимаете, о чём я говорю, EF-технология ORM «по-умолчанию».
Разумеется, чисто технически вам надо поставить соответствующий пакет.
Я считаю, что код по описанию в классах сущностей, их свойств и т.п. является однотипным, разве нет?
INotifyPropertyChanged
— однотипная.Представьте себе, да, надо знать заранее. Есть масса задач, где это надо. Например, есть устройство самообслуживания, не
имеющее постоянного доступа к БД. И ключи сущностей знать надо заранее, чтобы хотя бы логи потом разбирать, чтобы они были одинаковые, как в БД, так и на устройстве.
Вы предлагаете мне написать в каждый конструктор означивание первичного ключа. Или в каждом месте, где это потребуется. Сейчас у меня другой способ: в ORM, которую я юзаю, есть понятия «тип первичного ключа» и «генератор первичного ключа». И делаю я это декларативно, один единственный раз. Если мне нужно какой-то особенный закон генерации ключей (да, есть задачи, где недостаточно обычного GUID или целого), я пишу свой генератор и также один раз декларативно подключаю.
new
, что, в общем-то, нарушает простоту использования (и, кстати, прекрасно реализуется на EF). Если он в сущности, то это значит, что у вас не POCO-сущности, что нарушает чистоту модели (и, впрочем, все равно реализуется при работе с EF).Представляете, я не пишу никаких мапперов! Я просто декларативно определяю проекцию как множество собственных полей и полей связанных сущностей. И дальше её использую. Более того, такие множества специально именуются, так, что я всякий раз, когда мне надо, просто беру проекцию по имени, и всё. «Дай сущности в такой-то проекции». Всё. Более того, проекция задаётся прямо на диаграмме классов, визуально, в диалоговом режиме. Поверьте, делается это очень, очень быстро.
query.Project().To<YourProjectionName>()
.Представляете, когда я сейчас пишу прикладной код, я не думаю о CRUD, состояниях объектов, и какие там действия предпримет ORM (хотя могу). ORM делает это сам, как и резолвит зависимости между связанными сущностями. Ведь ежу понятно, что если я сделал new, будет только insert в БД, а если я что-то прочитал, то create всяко не будет.
Сама концепция ORM — очень хороша, т.к. повышает производительность труда.
ORM должен позволять настроить всё очень тонко и очень детально.
Вот обратно (проставить ключ и автоматически получить заполенное свойство) не работаетЕсли очень надо — нет проблем такое реализовать. Хотя код, конечно, чуть распухнет…
Мой аргумент прост: пока у вас 5-10-15 сущностей, вы можете держать структуру системы в голове. Пользуйтесь на здоровье! Когда счёт идёт на сотни, вы этого уже не можете.Так вот: сгенерированная по коду диаграмма, или даже несколько диаграмм — это отличный способ не запутаться в этих сущностях. Я понимаю, почему вам не подошли диаграммы классов — но почему вам не нравится нормальная диаграмма концептуальной модели БД?
Entity Framework глазами постороннего