Очевидно ваша база данных имеет Forms
и Products
.Существует отношение «один ко многим» между Forms
и Products
: каждый Form
имеет ноль или более Products
, каждый Product
принадлежит ровно одному Form
с использованием внешнего ключа (вероятно, Product.FormId
)
Ваш первый оператор выбирает один из ваших Forms
, который соответствует определенным требованиям, или ноль, если таких Form
нет.Не проверяя возвращаемое значение null, вы пытаетесь изменить Products
этого Form
.
Проблема в том, что может быть несколько Products
, которые имеют ненулевой внешний ключ для этого Form
.Они являются элементами в ICollection Products
формы.Если вы присваиваете новую коллекцию ICollection для Form.Products
, структура сущностей хочет установить внешний ключ Products
, который был в Form.Products
, равным нулю, указывая, что этот продукт больше не принадлежит ни к какой форме.Но в описании вашей модели вы определили, что каждый Product
должен принадлежать ровно одному Form
.Отсюда и ошибка.
То, что вы должны сделать, зависит от того, что вы хотите от вашей процедуры.Если вы хотите Получить форму с ее не удаленными продуктами , тогда вам следует выполнить запрос.Если вы хотите удалить все удаленные продукты из этих форм из базы данных , вам следует выполнить обновление
Запросить определенную форму с ее не удаленными продуктами
public ICollection<Form> GetFormWithNonDeletedProducts(string scode)
{
using (var dbContext = new MyDbContext(...))
{
return dBContext.Forms // from the collection of all Forms
.Where(form => form.Code == fCode
&& form.SCode == sCode) // keep only the ones that I want
.Select(form => new Form() // and create a new Form object
{ // with the properties I plan to use
Id = form.Id,
Name = form.Name,
...
Products = form.Products // Fetch only the non-deleted products
.Where(product => !product.Deleted)
.ToList(),
}
.FirstOrDefault();
}
}
}
Единственная причина, по которой мне нужно создать новый объект Product, заключается в том, что я хочу поместить его в возвращаемое значение.Если вам не нужно возвращаемое значение, вы можете поместить свои извлеченные свойства в анонимный объект.Обычно это более эффективно, потому что вы не будете получать данные, которые не будете использовать из базы данных.
Например, в приведенном выше примере будет назначено Product.FormId
.Вам это не понадобится, потому что вы знаете, что все тысячи Продуктов этой Формы будут иметь одинаковое значение FormId: а именно значение Form.Id
.
Тот же запрос без извлечения свойств, которые вы не используете (анонимные типы)
using (var dbContext = new MyDbContext(...))
{
return dBContext.Forms // from the collection of all Forms
.Where(form => form.Code == fCode
&& form.SCode == sCode) // keep only the ones that I want
.Select(form => new // and create a new Form object
{ // with the properties I plan to use
Id = form.Id,
Name = form.Name,
...
Products = form.Products // Fetch only the non-deleted products
.Where(product => !product.Deleted)
.Select(product => new
{ // Select only properties you plan to use
Name = product.Name,
Price = product.Price,
// not meaningful: you already know the value:
// FormId = product.FormId,
})
.ToList(),
}
.FirstOrDefault();
}
Обновите базу данных: удалите удаленные продукты в форме
Хотя ваша функция называется GetForms
, кажется, вы хотите использовать ее для удаления удаленных продуктов.
Самый простой способ - использовать DbSet<Products>.RemoveRange
:
using (var dbContext = new MyDbContext(...))
{
// remove all Deleted products of the form with Code equal to fCode
// and SCode equal to sCode
var productsToDelete = dbContext.Products
.Where(product => product.Deleted
&& product.Form.Code == fCode
&& product.Form.Scode == sCode);
// note: query is not executed yet!
dbContext.Products.RemoveRange(productsToDelete);
dbContext.SaveChanges();
}
Возможно, вам придется сделать RemoveRange(productsToDelete.ToList())
, вам придется проверить это.