У меня есть дизайн Entity Framework 4, который позволяет удалять ссылочные таблицы (без каскадного удаления) без изменения объектов, указывающих на них.Так, например, сущность A имеет ссылку внешнего ключа на сущность B в поле идентификатора.B можно удалить (и в базе данных нет ограничений FK, чтобы это остановить), поэтому, если я смотрю на ABID, это всегда допустимое поле (поскольку все, что он делает - возвращает поле идентификатора в A), даже если записи нетB с этим идентификатором из-за предыдущего удаления.Это сделано специально, я не хочу каскадного удаления, мне нужно, чтобы записи А оставались на некоторое время для целей аудита.
Проблема в том, что отфильтровать несуществующие удаленные записи не так простокак это звучит.Так, например, если я сделаю это:
from c in A
select A.B.somefield;
Это приведет к ВНЕШНЕМУ СОЕДИНЕНИЮ в сгенерированном SQL, поэтому он забирает все записи А, даже если они ссылаются на отсутствующие записи В.Итак, хак, который я использовал, чтобы решить эту проблему (поскольку я не могу найти лучший способ!), Это добавить условие where для проверки строкового поля в ссылочных B-записях.Если это поле в сущности B пустое, то я предполагаю, что B. не существует.
from c in A
where c.B.somestringfield != null
select A.B.somefield;
, кажется, работает, если B.somestringfield - строка.Если это целое число, это не сработает!
Это все для меня.Я думал о нескольких решениях, но они просто не практичны:
- Запросите все таблицы, которые ссылаются на B, когда B удален, и обнулите их внешние ключи.Это так уродливо, что я не хочу вспоминать об этом, если я добавлю другую сущность, которая ссылается на B в будущем.Не говоря уже об огромной задержке производительности, разрешающей все ссылки всякий раз, когда я что-то удаляю.
- Добавьте строковое поле в каждую таблицу, на которую я могу рассчитывать, чтобы быть там, чтобы проверить, существует ли сущность.Blech, я не хочу добавлять поле базы данных только для этого.
- Реализация мягкого удаления и сохранение всей ссылочной целостности без изменений - по сути, установка каскадного удаления, но это приведет к огромному раздутию базы данныхтак как я не могу очистить огромное количество записей из-за ссылок.Нет.
Я думал, что эту проблему вылизали с помощью трюка «проверить, является ли поле в ссылочной сущности нулевым», но он ломается в условиях, которые я до конца не понимаю (что, если янет строк в ссылочной таблице? Какие типы полей будут работать? Целые числа не будут.)
Например, если у меня есть целое поле "count" в сущности B, и я проверяю, чтобы увидетьесли оно равно нулю:
from c in A
where c.B.count != null
select c.B.count;
Я получаю кучу записей с нулем для подсчета, смешанным с результатами, и на самом деле запрос бомбардирует с "InvalidOperationException: приведение к значению типа Int32"не удалось из-за того, что материализованное значение является нулевым. Либо универсальный параметр результирующего типа, либо запрос должен использовать тип, допускающий значение NULL. "
Поэтому мне нужно сделать
from c in A
where c.B.count != null
select new { count = (int?)c.B.count };
, чтобы даже увидеть нулевые записи,Так что это довольно сбивает с толку, как этот запрос может привести к пустым записям в результатах вообще.
Я только что обнаружил, что если я сделаю явное соединение, как это, SQL будет INNER JOIN, и все прекрасно работает:
from c in A
join j in B on A.B.ID equals j.ID
select c;
Но это отстой.Мне придется изменить тонну запросов, чтобы добавить явные предложения соединения вместо того, чтобы наслаждаться удобством полей отношений, которые я получаю с EF.Кинда побеждает цель и добавляет еще много кода для поддержки.