for flooders
:: Главная :: Решения :: Статьи :: Сайт М. Дроздова :: Файловый архив :: Книга по VFP 9 :: Русский Help Online :: OFF-LINE Форум
   Л и с о в о д ы   в с е х   с т р а н,  о б ъ е д и н я й т е с ь !!!  

Список Форумов  :: Не фоксом единым
   :: Помощь сайту :: 

MS SQL sequence для default и Entity Framework
ou
Автор

Сообщений: 101
Дата: 13.02.18 11:52:03ОтветитьЦитировать
Здравствуйте, уважаемые коллеги!
Общая ситуация: есть БД MS SQL 2016, с которой работают приложения VFP 9.0 и C# с Entity Framework.
Понадобилось добавить в таблицы поле с ключом уникальным для БД. Этот ключ должен назначаться при добавлении записи, и потом его будут только читать, не изменять.
Для этого отлично подошло SQL sequence. То есть определена sequence SEQ1, а колонки в таблицы добавляются с DEFAULT (NEXT VALUE FOR [SEQ1]). Легко, быстро. Само поле - обыкновенное integer, не primary key.
И всё бы было распрекрасно, если бы не EF. Те, кто пишет C# часть, очень огорчились.

Сразу признаюсь: я об Entity Framework знаю чуть больше, чем ничего.
Из прочитанного мне удалось уяснить, что, во-первых, EF совсем не дружит с sequence, а во-вторых, как-то непросто дружит со значениями по умолчанию вообще. То есть нельзя просто так, имея DEFAULT для колонки в базе данных, совершенно не заботиться о том, что именно это за дефолт.
Вот такую мне дали ссылку про sequence: www.llblgen.com. Насколько я понимаю, из этого следует, что они, например, не могут использовать конструкцию вида .HasDefaultValueSql(...)
Насколько я понимаю, разработчики C#-части используют подход Data First (иначе и быть не может, потому что база уже есть, и все апгрейды всегда делаются SQL-скриптами).
Информация о DatabaseGenerated (например, отсюда www.learnentityframeworkcore.com), к сожалению, мне не очень помогла продвинуться в уяснении ситуации.

В общем, суть проблемы в том, что хочется иметь поле в БД MS SQL, значение которому должно присваиваться по умолчанию один раз при добавлении записи средствами самой БД. И хочется, чтобы это как-то совместилось с моделью в EF без изощренных танцев с бубном.
Не может ли кто-нибудь подсказать, куда двигаться дальше в поисках информации по EF? И возможно ли это вообще?
Ratings: 0 negative/0 positive

Re: MS SQL sequence для default и Entity Framework
Penner

Сообщений: 4046
Откуда: Muenster
Дата: 13.02.18 12:47:57ОтветитьЦитировать
не лучше ли?
uniqueidentifier + newid()


------------------
Никогда не откладывайте на завтра, то, о чем можно забыть навсегда
Ratings: 0 negative/0 positive

Re: MS SQL sequence для default и Entity Framework
ssa
[Модератор]

Сообщений: 11990
Откуда: Москва
Дата: 13.02.18 12:51:48ОтветитьЦитировать
Возможно, настроить что-то в EF для таких полей так же, как и для полей типа Timestamp. Тоже не редактируемое, тоже со значением не во власти EF.


------------------
Лень - это неосознанная мудрость.
Ratings: 0 negative/0 positive

Re: MS SQL sequence для default и Entity Framework
Igor Korolyov

Сообщений: 31334
Дата: 13.02.18 13:03:38ОтветитьЦитировать
Если данное поле не является первичным ключом, то что мешает использовать в маппинге для этого поля
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
Это хоть и CodeFirst подход, но он НЕ обязывает генерировать новую БД - вполне себе работает и с Legacy базами. Можно ли это делать через edmx я не в курсе, но сам по себе edmx-подход уже умер, слишком уж намудрили в MS с этим делом.

После сохранения записи в БД EF считает обратно значения для таких полей (для оракла это делается анонимным pl/sql блоком с командой вставки и возвратом "новых" значений - как для других СУБД я не в курсе, но полагаю что делается и достаточно надёжно).

Что именно и как именно используют ваши разработчики - это только у них и можно выяснить (а не гадать). В общем и целом я не в курсе существования каких-то "неразрешимых" проблем что с Sequence как таковыми (особенно для СУБД не имеющих identity, или попросту эмулирующих их через sequence тем или иным образом), что с другого рода "вычисляемыми при создании" полями. Возможно речь идёт про какую-то антикварную версию EF, или же ту или иную библиотеку-оболочку-апп_фреймворк работающую поверх EF и не предоставляющую все его возможности - но это тоже стоит уточнить у ваших разработчиков.

Вот с чем у EF могут быть серьёзные проблемы, так это с представлениями - особенно если они обновляемые (т.е. через них можно так или иначе изменять собственно данные в базовых таблицах).

Другое дело, что лично от меня ускальзывает смысл наличия поля заполняемого из sequence и НЕ являющегося первичным, или хотя-бы альтернативным ключом. Если таким образом вы собираетесь реализовывать нечто типа "непрерывной нумерации" документов или иных объектов, то ничего хорошего из этого у вас не получится - нумерация НЕ будет непрерывной.


------------------
WBR, Igor
Ratings: 0 negative/0 positive

Re: MS SQL sequence для default и Entity Framework
ou
Автор

Сообщений: 101
Дата: 13.02.18 13:54:55ОтветитьЦитировать
ssa
Возможно, настроить что-то в EF для таких полей так же, как и для полей типа Timestamp. Тоже не редактируемое, тоже со значением не во власти EF.
Подозреваю, что не получится. Для TimeStamp есть IsRowVersion() в Fluent API, а для использования sequence ничего нет.
Igor Korolyov
Если данное поле не является первичным ключом, то что мешает использовать в маппинге для этого поля
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
Мои скудные познания в EF заставляют подозревать, что это не то, что нужно. Надо, чтобы поле один раз проинициализировалось при добавлении записи и сохраняло бы это назначенное значение. Если я не ошибаюсь, Computed "subsequently regenerated every time the value is updated", а это не то, что нужно. Формально здесь, наверное, больше подходит .Identity, но что-то мне кажется, что одного DatabaseGenerated(DatabaseGeneratedOption.Identity) недостаточно.
Igor Korolyov
сам по себе edmx-подход уже умер
Его-то они и используют.
Igor Korolyov
нумерация НЕ будет непрерывной.
Непрерывность не требуется. Нужен просто уникальный код для каждой записи не на уровне таблицы, а на уровне БД. Есть еще отдельная таблица с полем primary key (не автоинкрементным), в которую после добавления записей в другие таблицы добавляются полученные из sequence ключи.
То есть схематично примерно так:
tabA (seqId DEFAULT (NEXT VALUE FOR [SEQ1]), val1 char(10)), tabB (seqId DEFAULT (NEXT VALUE FOR [SEQ1]), val2 char(20)), ......
tabId (Id integer CONSTRAINT [PK_tblId] PRIMARY KEY CLUSTERED ......
При добавлении записей в tabA, tabB, ..... в триггере INSERT AFTER добавляются записи со значениями соответствующих получившихся seqId в таблицу tabId.
Есть еще третья таблица tabUpd (seq Id FK(tabId.Id), updUser, updTime, updType, .......) - сюда логится информация об изменениях в таблицах tabA, tabB, ...
Если что, идея в целом не моя. Но мне нужно воплотить всё это в SQL.
Первоначально C#-щики предлагали tabId с автоинкрементным Id PK, в которую сначала нужно было добавлять запись, потом брать из нее Id и класть его во вновь добавленные записи таблиц tabA, tabB, ...
Насколько я понимаю, им это нужно было для того, чтобы связать поле seqId - Id с определением модели в EF (с @@IDENTITY EF работать может).
Но в этом случае всё как-то очень сложно и долго получается в триггерах INSERT, особенно, если одним инсертом добавляются несколько записей. Поэтому у меня возникла идея с использованием sequence. Верю, что не гениальная, но со стороны БД легко реализуемая.
Ratings: 0 negative/0 positive

Re: MS SQL sequence для default и Entity Framework
ou
Автор

Сообщений: 101
Дата: 13.02.18 13:58:28ОтветитьЦитировать
Penner
не лучше ли?
uniqueidentifier + newid()
Уж очень он здоровый. 16 байтов здесь явный перебор.
Ratings: 0 negative/0 positive

Re: MS SQL sequence для default и Entity Framework
Penner

Сообщений: 4046
Откуда: Muenster
Дата: 13.02.18 14:00:05ОтветитьЦитировать
за то, отлажено, быстро, уникально


------------------
Никогда не откладывайте на завтра, то, о чем можно забыть навсегда




Исправлено: Penner, 13.02.18 14:01
Ratings: 0 negative/0 positive

Re: MS SQL sequence для default и Entity Framework
Аспид

Сообщений: 3036
Откуда: Москва
Дата: 13.02.18 15:16:37ОтветитьЦитировать
ou
Уж очень он здоровый. 16 байтов здесь явный перебор.
И чем это смущает?
Зато с EF работает как часы.
Какая разница?)
А выбор sequence вообще не понятен, когда последовательность не нужна, и нужна уникальность во всей БД.
(Не понятные для меня требования)


------------------
Ratings: 0 negative/0 positive

Re: MS SQL sequence для default и Entity Framework
ou
Автор

Сообщений: 101
Дата: 13.02.18 15:36:04ОтветитьЦитировать
Аспид
И чем это смущает? Зато с EF работает как часы. Какая разница?)
Записей в таблице может быть много (миллионы). Не хочется на каждую навешивать еще 16 байтов. Опять же, если, например, индексировать, то лучше индекс по 4-хбайтовому числу, чем по 16-байтовому. Есть, правда, риск, что рано или поздно 4 байтов не хватит, но это уже другая проблема.
К тому же, насколько я понимаю, newid() - компьютерозависимый. Перепишут что-нибудь куда-нибудь, и возможно, будут проблемы с новыми значениями.
Аспид
А выбор sequence вообще не понятен, когда последовательность не нужна, и нужна уникальность во всей БД.(Не понятные для меня требования)
А чем плох sequence? Каждый раз генерится новое не повторяющееся число. Или я что-то не так понимаю? Быстро и просто.
Ratings: 0 negative/0 positive

Re: MS SQL sequence для default и Entity Framework
Igor Korolyov

Сообщений: 31334
Дата: 13.02.18 15:40:05ОтветитьЦитировать
ou
Igor Korolyov
Если данное поле не является первичным ключом, то что мешает использовать в маппинге для этого поля
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
Мои скудные познания в EF заставляют подозревать, что это не то, что нужно. Надо, чтобы поле один раз проинициализировалось при добавлении записи и сохраняло бы это назначенное значение. Если я не ошибаюсь, Computed "subsequently regenerated every time the value is updated", а это не то, что нужно. Формально здесь, наверное, больше подходит .Identity, но что-то мне кажется, что одного DatabaseGenerated(DatabaseGeneratedOption.Identity) недостаточно.
Computed просто предполагает что поле может изменяться со стороны сервера после начальной вставки - потому его EF будет считывать после любого update (скажем триггер в LastUpdate или Editor_Name поле, значение поменял). Если оно фактически не изменяется, то просто будет сделано немного лишней работы по его считыванию из БД и всё... Identity предполагает что поле изменяется сервером только во время вставки записи (соответственно после Update его "свежее" значение извлекаться не будет).

За Identity, возможно стоит специальная логика по извлечению автоинкрементного поля при работе с MSSQL, поэтому его возможно не удастся применить в данном конкретном случае. Тут как раз всё зависит от EF провайдера - такие тонкости реализации...

У меня нет MSSQL, а для оракла оба варианта DatabaseGeneratedOption работают с LastUpdate полем изменяемым триггерами (на insert и update). Разница именно в том, что для Identity считывается значение лишь один раз (конечно же в рамках сессии/контекста, для новой сессии/контекста будет извлечён "свежачок"), даже если я делаю создание-модификацию-модификацию для этого объекта (с явным сохранением после каждой такой операции - иначе до БД объект и не дойдёт, и никакие БД генераторы значений не сработают ).

Кстати, для EFCore уже по иному конфигурируется этот аспект свойств в его FluentAPI. Вместо .HasDatabaseGeneratedOption(DatabaseGeneratedOption.***) там есть три отдельных метода с "говорящими" именами: ValueGeneratedOnAddOrUpdate(), ValueGeneratedOnAdd() и ValueGeneratedNever()
В "аннотациях" по прежнему используется атрибут DatabaseGenerated с одним из значений перечисления DatabaseGeneratedOption...


------------------
WBR, Igor
Ratings: 0 negative/0 positive

Re: MS SQL sequence для default и Entity Framework
Penner

Сообщений: 4046
Откуда: Muenster
Дата: 13.02.18 15:50:23ОтветитьЦитировать
ну если хочется изобретать велосипед с квадратными колёсами...


------------------
Никогда не откладывайте на завтра, то, о чем можно забыть навсегда
Ratings: 0 negative/0 positive

Re: MS SQL sequence для default и Entity Framework
ou
Автор

Сообщений: 101
Дата: 13.02.18 15:56:50ОтветитьЦитировать
Igor Korolyov
Computed просто предполагает что поле может изменяться со стороны сервера после начальной вставки - потому его EF будет считывать после любого update
Звучит обнадеживающе. Попрошу их попробовать. Спасибо.
Penner
ну если хочется изобретать велосипед с квадратными колёсами...
Не, не хочется. Но не нравятся мне эти 16 байтов
Всем за советы спасибо
Ratings: 0 negative/0 positive

Re: MS SQL sequence для default и Entity Framework
Igor Korolyov

Сообщений: 31334
Дата: 13.02.18 17:43:43ОтветитьЦитировать
Кстати, по схеме - в чём смысл таблицы tabId? Какие там ещё поля заведены и что они будут хранить? По логу в таблице tabUpd как раз понятно - история любой отслеживаемой записи, но вот эта tabId для чего? Чисто как "служебная" для генерации id методом identity - ну это понятный костыль для версий MSSQL без sequence и при нежелании использовать здоровенный guid, или всякие хитрые схемы с композитными ключами типа id+tableName... Для поддержания FK от рабочих таблиц? Так я бы не стал вообще делать FK с "рабочих" таблиц на таблицу лога - это накладно, может приводить к совсем ненужной contention при работе с такой БД (вводится "бутылочное горлышко" - при вставке в любую таблицу лишняя проверка на наличие ключа в этой таблице)... Я всё же не вижу "бизнес-сущности" у такого рода таблиц логов/аудита - это скорее служебные данные, и потому поддерживать там полноценную RI целостность... Ладно бы это было "бесплатно", а так Уже сам по себе этот аудит неплохо просадит производительность БД, и "усугублять" это дело не очень хорошо.


------------------
WBR, Igor




Исправлено: Igor Korolyov, 13.02.18 17:45
Ratings: 0 negative/0 positive

Re: MS SQL sequence для default и Entity Framework
ou
Автор

Сообщений: 101
Дата: 14.02.18 12:37:11ОтветитьЦитировать
Igor Korolyov
Кстати, по схеме - в чём смысл таблицы tabId? Какие там ещё поля заведены и что они будут хранить?
Сейчас ничего там нет.
Igor Korolyov
Чисто как "служебная" для генерации id методом identity - ну это понятный костыль для версий MSSQL без sequence
Как я понимаю - именно костыль, но не из-за особенностей SQL, а из-за EF. Они из C# тоже добавляют записи и сначала пишут запись в tabID, а потом используют Id из нее.
Кстати, моего совета, данного по Вашей подсказке, они не послушали. Сказали, что такого не знают и пробовать боятся.
Пришлось мне менять триггеры и делать так же - добавлять запись в tabId и использовать код
Igor Korolyov
Для поддержания FK от рабочих таблиц? Так я бы не стал вообще делать FK с "рабочих" таблиц на таблицу лога - это накладно, может приводить к совсем ненужной contention при работе с такой БД (вводится "бутылочное горлышко" - при вставке в любую таблицу лишняя проверка на наличие ключа в этой таблице)... Я всё же не вижу "бизнес-сущности" у такого рода таблиц логов/аудита - это скорее служебные данные, и потому поддерживать там полноценную RI целостность... Ладно бы это было "бесплатно", а так Уже сам по себе этот аудит неплохо просадит производительность БД, и "усугублять" это дело не очень хорошо.
Тысячу раз да! Только связь по FK там не организована (возможно, пока) в расчете на то, что всё всегда будет работать правильно. Надо будет написать им, какие недостатки есть у такого способа. Может, одумаются
Ratings: 0 negative/0 positive

Re: MS SQL sequence для default и Entity Framework
Igor Korolyov

Сообщений: 31334
Дата: 14.02.18 12:59:33ОтветитьЦитировать
Честно говоря для меня странно что аудит реализуется силами клиентского ПО, а не целиком на сервере. Конечно, если это именно аудит, а не какая-то хитрая часть бизнес-процесса


------------------
WBR, Igor
Ratings: 0 negative/0 positive

Re: MS SQL sequence для default и Entity Framework
ou
Автор

Сообщений: 101
Дата: 14.02.18 14:25:47ОтветитьЦитировать
Igor Korolyov
Честно говоря для меня странно что аудит реализуется силами клиентского ПО, а не целиком на сервере. Конечно, если это именно аудит, а не какая-то хитрая часть бизнес-процесса
Именно и только аудит (пока, во всяком случае). Боятся триггеров. Согласились на триггеры для учета изменений из фоксовской части, потому что считается, что она скоро уйдет в небытие. Хотя она туда уходит уже пару лет, и всё никак уйти не может.
Ratings: 0 negative/0 positive

Re: MS SQL sequence для default и Entity Framework
Гулин Федор

Сообщений: 3809
Откуда: Минск
Дата: 14.02.18 14:59:44ОтветитьЦитировать
я тоже по прошлому опыту против GUID
www.llblgen.com

The Entity framework doesn't support sequence mapping, OTHER than mapping of system sequences (e.g. @@IDENTITY or SCOPE_IDENTITY()). This means that when you use a database which requires the usage of schema sequences, like Oracle or PostgreSql, the sequences assigned to mappings are ignored by the as there's no way to specify the usage of a specific sequence in the Entity Framework's Edmx file.

насколько я понимаю англ. - то как раз @@IDENTITY or SCOPE_IDENTITY() поддерживаются !
т.е пиши в мапинг или то ли это в зависимосит что надо. - одна из них глобальная др. в рамках сессии
Ratings: 0 negative/0 positive

Re: MS SQL sequence для default и Entity Framework
ou
Автор

Сообщений: 101
Дата: 14.02.18 15:32:31ОтветитьЦитировать
Гулин Федор
насколько я понимаю англ. - то как раз @@IDENTITY or SCOPE_IDENTITY() поддерживаются !
т.е пиши в мапинг или то ли это в зависимости что надо. - одна из них глобальная др. в рамках сессии
Да, но нужен Id не для одной таблицы, а общий для нескольких таблиц одновременно.
В EF пишу не я, я пишу в фоксе .
Но может быть, в EF и можно примапить как @@IDENTITY чисто формально - таких тонкостей я не знаю. Надо собраться и попробовать. Чай, не боги горшки обжигают
Хотя, если указать в EF @@IDENTITY как значение по умолчанию для таблиц tabA, tabB, ... из примера, то это, наверное, будет работать, если прямо перед этим добавлена запись в tabId. Хотя мне непонятно, как при этом легко и просто обеспечить из C#, чтобы между добавлением в tabId и добавлением в tabA, tabB не успело добавиться что-нибудь еще в базе ....
Но это не решает проблему в случае с использованием sequence.
В общем, стоит попробовать Computed, я думаю.



Исправлено: ou, 14.02.18 15:53
Ratings: 0 negative/0 positive

Re: MS SQL sequence для default и Entity Framework
Igor Korolyov

Сообщений: 31334
Дата: 14.02.18 20:53:24ОтветитьЦитировать
Гулин Федор
насколько я понимаю англ. - то как раз @@IDENTITY or SCOPE_IDENTITY() поддерживаются !
т.е пиши в мапинг или то ли это в зависимосит что надо. - одна из них глобальная др. в рамках сессии

Не понимаю какое отношение цитируемый тут продукт "LLBLGen Pro" имеет к возможностям собственно EF...

Сам же EF просто не может (хотя на сегодня я сильно не уверен в этом, в том же оракле есть хитрая поддержка identity - через автогенерируемые sequence и внутренний механизм сходный с default, насколько я понимаю - плюс от самого оракла ef-провайдер, наверняка это всё распознающий) СОЗДАТЬ корректную структуру БД из метаописаний (тем паче obsolete-ный edmx) с использованием sequence. Т.е. это ограничение для CodeFirst подхода.
Работать же с таблицей оракла на которой висит старый добрый тригер (как в pre-12c эру) заполняющий поле (id или не id - уверен это без разницы) из sequence - нет решительно никаких проблем. Т.е. если и будут вопросы, то к части создания структуры БД и "миграций", что автору вопроса совершенно точно не важно

ou
Именно и только аудит (пока, во всяком случае). Боятся триггеров.
Нда, плохо когда нет DBA способного научить, а то и просто вправить мозги неграмотным в этой части разрабам...
Аудит силами прикладной части ПО - это не аудит а фикция. При том ещё и геморройно реализуемый.


------------------
WBR, Igor
Ratings: 0 negative/0 positive



Извините, только зарегистрированные пользователи могут писать в этом форуме.

On-line: 40 and Guests: 40


© 2000-2018 Fox Club 
Яндекс.Метрика