Предотвратите повторные попытки DbContext сохранить неверные данные

StackOverflow https://stackoverflow.com//questions/24001698

Вопрос

У меня есть процесс, который импортирует электронную таблицу Excel и преобразует данные в мои объекты данных.Источником этих данных является очень сомнительно, поскольку мы переводим нашего клиента с управления данными на основе электронных таблиц на управляемую систему баз данных с проверкой достоверности данных.

В процессе импорта я выполняю некоторые базовые проверки работоспособности данных, чтобы понять, насколько плохими могут быть данные, которые мы импортируем, но общая проверка выполняется в DbContext.

Часть того, что я пытаюсь сделать, заключается в том, что я хочу указать строку # в электронной таблице, в которой указаны неверные данные, чтобы они могли легко определить, что им нужно исправить, чтобы получить файл для импорта.

Как только у меня будут данные из электронной таблицы (model), и возможность, с которой они работают из базы данных (opp), вот псевдокод моего процесса:

foreach (var model in Spreadsheet.Rows) { // Again, pseudocode
    if(opp != null && ValidateModel(model, opp, row)) {
        // Copy properties to the database object

        // This is in a Repository-layer method, not directly in my import process.
        // Just written here for clarity instead of several nested method calls.
        context.SaveChanges(); 
    }
}

Я могу предоставить здесь больше кода, если это необходимо, но проблема возникает в моем DbContext ValidateEntity() метод (переопределение DbContext).

Опять же, насколько мне известно, в написанном мной коде нет ничего плохого, но если Opportunity не прошла проверку на этом уровне, то она остается как часть несохраненных объектов в context, что означает , что он повторно пытается пройти проверку каждый раз , когда ValidateEntity() называется.Это приводит к повторению одного и того же сообщения об ошибке проверки для каждой строки после возникновения первоначальной проблемы.

Есть ли способ [править / править код]заставьте Контекст прекратить попытки проверки объекта после того, как он один раз не прошел проверку[править]?Я знаю, что мог бы дождаться конца и позвонить context.SaveChanges() один раз в конце, чтобы обойти это, но я хотел бы иметь возможность сопоставить это с тем, какая строка находится в базе данных.

Для справки, я использую Entity Framework 6.1 с подходом "Сначала код".

Редактировать Попытка внести дополнительные ясности для Марка Л.(включая обновление приведенного выше блока кода)

Прямо сейчас мой процесс будет перебирать столько строк, сколько есть в электронной таблице.Причина, по которой я вызываю свой уровень репозитория с каждым объектом для сохранения, вместо того, чтобы работать с подходом, который вызывает только context.SaveChanges() один раз - это позволить себе определить, какая строка является причиной ошибки проверки.

Я рад, что мой DbContext является пользовательским ValidateEntity() методы улавливают ошибки проверки, но проблема заключается в том, что они не выдают DbEntityValidationException для одного и того же объекта несколько раз.

Мне бы хотелось, чтобы, если объект не прошел проверку один раз, контекст больше не пытался сохранить объект, независимо от того, сколько раз context.SaveChanges() называется.

Это было полезно?

Решение

Ваш вопрос не является обманом (речь идет о сохранении, а не о загруженных объектах), но вы могли бы последовать совету Джимми, приведенному выше.То есть, как только объект добавляется в контекст, он отслеживается в состоянии "добавлено", и единственный способ остановить его повторную проверку - это отсоединить его.Это ТАК называемая внутренняя ссылка, но я воспроизведу фрагмент кода:

dbContext.Entry(entity).State = EntityState.Detached;

Однако я не думаю, что это тот путь, которым вы хотите пойти, потому что вы используете исключения для ненужного управления состоянием (исключения, как известно, очень дороги).

Основываясь на приведенной информации, я бы использовал более основанное на множествах решение:

  • измените свой класс модели так, чтобы он содержал RowID, который записывает исходную строку электронной таблицы (вероятно, есть и другие веские причины для этого)
  • отключите отслеживание сущностей для контекста (повороты обнаружения изменений, позволяющие каждому Add() быть O(1))
  • добавьте все объекты
  • звонить context.GetValidationErrors() и получите все ваши ошибки сразу, используя вышеупомянутый RowID для идентификации недопустимых строк.

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


Наконец, если вы действительно хотите сохранить хорошие строки и вам неудобен метод, основанный на множестве, было бы лучше использовать новый DbContext для каждой отдельной строки или, по крайней мере, создайте новую DbContext после каждой ошибки.ADO.NET Команда настаивает на том, что создание контекста "относительно дешево" (извините, у меня нет под рукой ссылки или статистики для этого), поэтому это не должно слишком сильно повредить вашей пропускной способности.Тем не менее, он, по крайней мере, останется O (n).Я бы не стал вас винить, но управление большим контекстом может открыть вам доступ и к другим проблемам.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top