Форум программистов, компьютерный форум, киберфорум
C#: Базы данных
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.57/7: Рейтинг темы: голосов - 7, средняя оценка - 4.57
54 / 53 / 5
Регистрация: 14.08.2012
Сообщений: 252

EntityFramework 6. Disconnected Scenario. Удалить, добавить или изменить две связанные сущности

16.01.2017, 23:24. Показов 1427. Ответов 5
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Предположим, что у нас есть две таблицы в базе - Client и Address. Причём у Client есть внешний ключ на адрес типа int?
Требуется удалить, добавить или изменить одну из записей в таблице Client вместе с его Address, если он имеется. Скопировать сведения об этих сущностях в другой контекст и сохранить эти изменения там.
У меня есть такая проблема:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Client clientCopy = null;
Address = addrCopy = null;
 
using (var context = new MyContext())
{
    Client client = context.Client.First();
    Address addr = client.Address;
    
    if (addr != null)
        context.Address.Remove(addr); // у client свойство Address сбрасывается на null
 
    context.Client.Remove(client);
 
    // context.SaveChanges(); - здесь сохранение сработало бы как надо.
 
    // Методы копирования выполняются именно в конце, т.к. пользователь мог бы просто отредактировать данные без 
    // удаления
    clientCopy = Entity.GetCopy(client) as Client; // Метод просто создаёт новый объект и копирует все его свойства
    addrCopy = Entity.GetCopy(addr) as Address;
}
 
using (var context = new MyContext())
{
    DbEntityEntry e1 = context.Entry(clientCopy); // здесь у clientCopy свойство Address равно null
    DbEntityEntry e2 = context.Entry(addrCopy);
 
    e1.State = EntityState.Deleted;
    e2.State = EntityState.Deleted;
    
    context.SaveChanges(); // Бросает исключение, на ограничение внешнего ключа при операции DELETE.
    // Потому что сущности clientCopy и addrCopy в этом контексте никак не связаны и 
    // фреймворк пытается удалять объекты в каком-то своём порядке, - сначала адрес, а потом клиента, не обращая внимания на порядок их удаления в коде (было выявлено с помощью Database.Log).
 
    // Как мне указать в этом контексте, что эти сущности нельзя удалять просто так по отдельности? 
    // Откуда извлечь информацию об их разорвавшейся связи и как можно это задать?
}
Пример кода приведён коротко и искусственно на основании большой реальной задачи, но он демонстрирует проблему, которая у меня возникла. С редактированием и добавлением таких проблем нет.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
16.01.2017, 23:24
Ответы с готовыми решениями:

Добавить или Изменить/Удалить
Есть таблица с полями id, id_doc, name, sum. Заполняется так по содержимому документа id_doc уникальный идентификатор документа, name -...

System.Data.DataSet. Две связанные таблицы, добавить строчку в одну из них
как построить такую вещь? например, хочу иметь две таблицы: отделы (название, идентификатор_отдела, прочее) сотрудники (фио,...

Как добавить, удалить или изменить запись в ListBox, чтобы при этом изменения сохранились в базе данных?
Как добавить, удалить или изменить запись в Listbox, чтобы при этом изменения сохранились в базе данных??? Кто нибудь может помочь с кодом...

5
Эксперт .NET
 Аватар для Usaga
14103 / 9320 / 1349
Регистрация: 21.01.2016
Сообщений: 34,999
17.01.2017, 07:55
AceOfSpades, ознакомься со статьёй. Обрати внимание на вызов метода DbSet<T>.Attach().
0
54 / 53 / 5
Регистрация: 14.08.2012
Сообщений: 252
17.01.2017, 18:48  [ТС]

Не по теме:

К сожалению, могу отвечать только вечером



Цитата Сообщение от Usaga Посмотреть сообщение
ознакомься со статьёй. Обрати внимание на вызов метода DbSet<T>.Attach().
Это всё мне известно. Какое отношение это имеет к моей проблеме? Лучше помогите решить задачу, гуглить я умею.
0
Эксперт .NET
 Аватар для Usaga
14103 / 9320 / 1349
Регистрация: 21.01.2016
Сообщений: 34,999
17.01.2017, 19:22
AceOfSpades, мне, мягко говоря, не совсем ясно что ты хочешь сделать и зачем. Зачем нужно удалять сущности в одном контексте, а потом тащить их трупики в другой и там их добивать изменением состояние? Чтобы наверняка удалились и не воскресли?

А ссылку я не просто так дал. Там речь идёт о disconnected scenario. Когда сущность вытаскивается из контекста (который, к примеру приберается), а потом может быть сохранена в другом экземпляре контекста. Чтобы ты тут не спрашивал, такой сценарий работы с EF наверняка тебе подходит.

Ну или в деталях разъясни свою задумку, ибо у меня есть подозрение, что ты пытаешь сделать что-то ну очень неправильное.
0
54 / 53 / 5
Регистрация: 14.08.2012
Сообщений: 252
17.01.2017, 20:13  [ТС]
Задумка вот в чём:

Вместо того, чтобы придумывать какие-то свои классы для отслеживания изменений пользователя, я просто беру уже готовое - контекст EF, который всё это за меня делает (ленивая загрузка, изменение связей и прочее). Этот контекст "чистовой", в котором находится весь граф сущностей загруженных из базы (кроме редактируемых полей есть еще таблицы-справочники, которых может быть пару десятков и в каждом по нескольку тысяч строк) - весь этот объем довольно немаленький, чтобы просто взять и пересоздать контекст как рекомендуют многие.
Очень часто на практике требуется реализовать работу по редактированию данных типа Master - Details, что само по себе уже намекает на возможность их отдельного сохранения/обновления/отмены. Как редактировать Master - Details из разных контекстов я, честно, не представляю. Извращения вроде передачи идентификатора мастер-строки, чтобы по нему загрузить details в другом контексте и их редактировать - приводят к лютому говнокоду в любом проекте и допустимы только для очень простых моделей данных (я уже молчу про структуры типа Master - Details - AdditionDetails).
Так вот. Всю информацию об изменениях сущностей мы можем получить через Entry. На основании этого можно создать временный контекст, поместить в него нужную часть измененных сущностей и сохранить их там. В случае ошибки мы просто убиваем этот контекст и имеем возможность исправить всё что нужно и повторить попытку. В случае успешного сохранения всем изменённым сущностям из "чистового" контекста просто задаём State = Unchanged. Соответственно всем добавленным сущностям придётся проставить созданный при сохранении идентификатор перед тем как делать State = Unchanged. Для удаленных делаем State = Detached.
У меня этот механизм уже написан и он работает (и каскадное удаление тоже). Кроме вышеуказанного случая, когда связь полностью разорвана (хотя "чистовой" контекст где-то хранит информацию даже о таком случае, но мне пока не удаётся найти способ перенести её во временный).
0
Эксперт .NET
 Аватар для Usaga
14103 / 9320 / 1349
Регистрация: 21.01.2016
Сообщений: 34,999
18.01.2017, 06:38
Цитата Сообщение от AceOfSpades Посмотреть сообщение
приводят к лютому говнокоду в любом проекте и допустимы только для очень простых моделей данных
Цитата Сообщение от AceOfSpades Посмотреть сообщение
Этот контекст "чистовой", в котором находится весь граф сущностей загруженных из базы (кроме редактируемых полей есть еще таблицы-справочники, которых может быть пару десятков и в каждом по нескольку тысяч строк) - весь этот объем довольно немаленький, чтобы просто взять и пересоздать контекст как рекомендуют многие.
Не находишь, что эти вещи связаны?

Цитата Сообщение от AceOfSpades Посмотреть сообщение
Как редактировать Master - Details из разных контекстов я, честно, не представляю.
Я тебе в другой теме уже показывал, что нет проблем отдельно зависимую сущность загрузить, не трогая корневую\родительскую.

Вот это мне не очень понятно:
Цитата Сообщение от AceOfSpades Посмотреть сообщение
Извращения вроде передачи идентификатора мастер-строки, чтобы по нему загрузить details в другом контексте и их редактировать - приводят к лютому говнокоду в любом проекте и допустимы только для очень простых моделей данных (я уже молчу про структуры типа Master - Details - AdditionDetails).
Ты получаешь ID сущности, получаешь по нему некую другую, зависимую сущность, редактируешь и сохраняешь. В чём здесь говнокод? Может быть ты пробовал такое сделать и именно твоя реализация вышла говнокодом, но это не распространяется автоматом на всех.

Идея использовать один из контекстов в виде кеша - очень плоха. Во-первых, потому, что контексты в EF ограничивают размер этого самого кеша восемью сотнями единиц (пруф, 3.2.2 Cache eviction algorithm), во-вторых, потому, что это и есть говнокод от которого ты так хотел уйти, ну и скорость поиска сущностей в кеше EF падает нелинейно с ростом этого кеша. Поэтому, хорошей практикой является использование короткоживущих (dicsonnected scenario) контекстов: создал контекст - вытащил сущность\приаттачил - сохранил - закрыл. Ну и трекинг изменений можно отключить.

Нет никакой проблемы дёргать сущность из БД каждый раз, при необходимости. Если речь идёт о справочниках, то их можно (и, в зависимости от ситуации, нужно) кешироть отдельно, своим механизмом (или встроенным).

Собственно, я вижу проблему при проектировании архитектуры или неполное\неверное понимание работы EF и принципов его использования.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
18.01.2017, 06:38
Помогаю со студенческими работами здесь

Связанные сущности Doctrine2
Здравствуйте, у меня был и есть интернет магазин на KO3 Сейчас я портирую его на последнюю стабильную версию Symfony 2.6 в которой я пока...

Doctrine 2 и связанные сущности
Как реализовать связь, при которой в качестве внешнего ключа выступает id другой таблицы? Проблема в том, что при каскадном обновлении...

Как лучше организовать бизнес-логику и сильно связанные сущности
Доброго времени суток! Суть вот в чем. В модели Entity Framework (db first) имеется несколько сущностей, допустим &quot;Заявка&quot; и...

Удалить из файла две первые и две последние строки и добавить строки с экрана в начало и конец файла
Задание: Создать текстовый файл. Заполнить его произвольным числом строк. Удалить из файла две первые и две последние строки и...

Dbforge s for oracle изменить,добавить и удалить
Я вот добавила таблицу,все заполнила при помощи цикла,теперь я хочу изменять там данные или удалять их,как это можно сделать ?и ещё...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Новые блоги и статьи
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru