Вопрос или проблема
Как я могу исправить это исключение?
InnerException = {"Не удалось вставить значение NULL в столбец 'IsDeleted', таблица 'snapshot2_new.dbo.Workflows'; столбец не допускает NULL. Вставка не удалась.\r\nОперация была прервана."}
Это происходит в этом методе:
public async Task<Workflow> CopyWorkflow(int id, int userId)
{
var wf = await this._context.Workflows
.Include(w => w.WorkflowStages)
.ThenInclude(s => s.Questions)
.Include(w => w.WorkflowStages)
.ThenInclude(s => s.StageTimeLimits)
.Include(w => w.WorkflowStages)
.ThenInclude(s => s.RequiredDocumentation)
.Include(w => w.WorkflowStages)
.ThenInclude(s => s.DocumentCategories)
.Include(w => w.WorkflowStages)
.ThenInclude(s => s.RolesCanUpdateStage)
.AsNoTracking() // Обеспечивает, что нет отслеживания, чтобы предотвратить проблемы с оригинальной сущностью
.AsSplitQuery()
.FirstOrDefaultAsync(w => w.Id == id);
if (wf == null)
{
throw new Exception("Рабочий процесс не найден.");
}
// Сбросить столбец идентификатора и другие свойства
wf.Id = 0; // Сбросить Id, чтобы база данных могла назначить новый
wf.IsRetired = false;
wf.IsDeleted = false;
wf.DateCreated = DateTime.Now;
wf.DateUpdated = DateTime.Now;
// Добавить изменённый рабочий процесс в контекст
_context.Workflows.Add(wf);
await _context.SaveChangesAsync(); // Использовать асинхронное сохранение
return wf;
}
Я остановился с отладчиком перед сохранением и у wf значение false для IsDeleted:
это запрос, сгенерированный Entity Framework
[23:44:36 ERR] Не удалось выполнить DbCommand (20ms) [Parameters=[@p0='?' (DbType = DateTime2), @p1='?' (DbType = DateTime2), @p2='?' (DbType = Boolean), @p3='?' (DbType = Boolean), @p4='?' (DbType = Boolean), @p5='?' (DbType = Boolean), @p6='?' (DbType = Int32), @p7='?' (DbType = Int32), @p8='?' (Size = 4000), @p9='?' (DbType = Int32)], CommandType="Text", CommandTimeout="30"]
SET NOCOUNT ON;
INSERT INTO [Workflows] ([DateCreated], [DateUpdated], [IsEnabledDocumentTemplates], [IsQVAccountsProductionRequired], [IsRetired], [IsTemplate], [ManagingAgentId], [UserId], [WorkflowTitle], [WorkflowTypeId])
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9);
SELECT [WorkflowId], [IsDeleted]
FROM [Workflows]
WHERE @@ROWCOUNT = 1 AND [WorkflowId] = scope_identity();
Ответ или решение
Чтобы решить проблему с ошибкой вставки в базу данных, вызванной тем, что столбец IsDeleted
не может быть равен NULL
, вам нужно убедиться, что вы правильно присваиваете значение для этого столбца перед добавлением нового объекта в контекст Entity Framework.
В вашем коде вы уже присваиваете значение false
для wf.IsDeleted
, однако причина ошибки может заключаться в том, что Entity Framework не отслеживает данный объект как изменяемый, потому что вы используете метод AsNoTracking()
. Это может привести к тому, что изменения, которые вы сделали в объекте wf
, не будут распознаны при сохранении в базе данных.
Вот как вы можете исправить проблему:
-
Уберите метод
AsNoTracking()
из вашего запроса, чтобы Entity Framework мог отслеживать изменения объектов после их извлечения из базы данных. -
Если вы по каким-то причинам хотите оставить
AsNoTracking()
, вам нужно создать новый объект, который будет копиейwf
, и установить значения свойств, включаяIsDeleted
.
Окончательная версия вашего метода CopyWorkflow
может выглядеть следующим образом:
public async Task<Workflow> CopyWorkflow(int id, int userId)
{
var wf = await this._context.Workflows
.Include(w => w.WorkflowStages)
.ThenInclude(s => s.Questions)
.Include(w => w.WorkflowStages)
.ThenInclude(s => s.StageTimeLimits)
.Include(w => w.WorkflowStages)
.ThenInclude(s => s.RequiredDocumentation)
.Include(w => w.WorkflowStages)
.ThenInclude(s => s.DocumentCategories)
.Include(w => w.WorkflowStages)
.ThenInclude(s => s.RolesCanUpdateStage)
.FirstOrDefaultAsync(w => w.Id == id);
if (wf == null)
{
throw new Exception("Workflow not found.");
}
// Создание нового экземпляра Workflow и копирование значений
var newWorkflow = new Workflow()
{
Id = 0, // Сброс идентификатора для автогенерации в БД
IsRetired = false,
IsDeleted = false, // Убедитесь, что вы устанавливаете IsDeleted
DateCreated = DateTime.Now,
DateUpdated = DateTime.Now,
// Копируйте другие свойства из wf, если это необходимо
// Например, если у Workflow есть другие свойства, их также нужно задать здесь
// WorkflowStages = wf.WorkflowStages.Select(stage => new WorkflowStage
// {
// // Укажите необходимые свойства
// }).ToList()
};
// Добавьте новый Workflow в контекст
_context.Workflows.Add(newWorkflow);
await _context.SaveChangesAsync(); // Асинхронное сохранение
return newWorkflow;
}
Таким образом, вы создаете новый объект newWorkflow
, который будет правильно добавлен в базу данных с заданным значением поля IsDeleted
, и это должно устранить проблему с ошибкой вставки. Не забудьте также копировать другие необходимые свойства, если они требовательны в вашей логике.