[英]How to get reference for child entries of the parent in one-to-many relationship?
[英]one2many relation, get parent with child
public void getForm(string scode) {
Form result = DBContext.Forms.Where(f => f.Code == fCode && f.SCode == sCode).FirstOrDefault();
result.Products = result.Products.Where(p => p.Deleted== false).ToList(); // commenting this line fix the problem
return result;
}
我們如何將兩行以上合並在一起以避免出現以下錯誤。
操作失敗:由於一個或多個外鍵屬性不可為空,因此無法更改該關系。 對關系進行更改時,相關的外鍵屬性將設置為空值。 如果外鍵不支持空值,則必須定義新的關系,必須為外鍵屬性分配另一個非空值,或者必須刪除不相關的對象。
更新:
當在另一個函數中調用時,它拋出錯誤
public void savetrans(string fcode)
{
Form form = GetForm(fCode);
var transDb = new DbContext.Data.Transaction()
{
FId = form.FId,
field1= "test",
field2= "test",
field3= "test",
};
DbContext.Transactions.Add(transactionDb);
DbContext.SaveChanges();
}
如果要刪除標記為已刪除的產品:
var deletedProducts = result.Products.Where(x => x.Deleted).ToList();
foreach(var deletedProduct in deletedProducts)
result.Products.Remove(deletedProduct);
如果Form.Products是List<Product>
則可以使用.RemoveAll(x => x.Deleted)
如果您只想在與實體合作時排除已刪除的產品,則建議為此目的使用未映射的屬性:
public class Form
{
public ICollection<Product> Products { get; set; } = new List<Product>();
[NotMapped]
public IReadOnlyCollection<Product> ActiveProducts => Products.Where(x => !x.Deleted).ToList().AsReadOnly();
// or
public IReadOnlyCollection<Product> ActiveProducts
{
get { return Products.Where(x => !x.Deleted).ToList().AsReadOnly();
}
}
然后,當您只想使用活動產品時,請使用.ActiveProducts
。 這種方法的警告是您不能在EF Linq表達式中使用此屬性,而只能以只讀方式使用。 例如,請勿嘗試以下操作:
var products = context.Forms.Where(x => x.FormId == formId).SelectMany(x => x.ActiveProducts);
這將出錯,因為EF不會映射ActiveProducts。 您必須將.Products與“已刪除”的相應過濾器一起使用。
我通常會在填充視圖模型時而不是在實體級別上放置諸如處理活動/非活動之類的邏輯。 實體應反映數據模型,而適用於您如何查看/與該邏輯交互的業務邏輯則由視圖模型表示。 使用視圖模型的好處是,填充視圖模型后,只需檢查一次“活動/已刪除”狀態,它們就不會使用在某些用途中無效的屬性來毒害實體。
顯然,您的數據庫具有Forms
和Products
。 Forms
和Products
之間存在一對多的關系:每個Form
都有零個或多個Products
,每個Product
使用外鍵(可能是Product.FormId
)完全屬於一個Form
您的第一條語句將提取您的一個滿足某些要求的Forms
,如果沒有這樣的Form
,則為null。 在不檢查null返回值的情況下,您嘗試更改此Form
的Products
。
問題是,可能有多個Products
對此Form
具有不可為空的外鍵。 它們是表單Products
的ICollection中的項目。 如果您分配一個新的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
。 你不需要它,becasue你知道,這種形式的所有千的產品將具有相同的值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())
,您必須檢查一下。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.