簡體   English   中英

一個一對多的關系,帶孩子的父母

[英]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與“已刪除”的相應過濾器一起使用。

我通常會在填充視圖模型時而不是在實體級別上放置諸如處理活動/非活動之類的邏輯。 實體應反映數據模型,而適用於您如何查看/與該邏輯交互的業務邏輯則由視圖模型表示。 使用視圖模型的好處是,填充視圖模型后,只需檢查一次“活動/已刪除”狀態,它們就不會使用在某些用途中無效的屬性來毒害實體。

顯然,您的數據庫具有FormsProducts FormsProducts之間存在一對多的關系:每個Form都有零個或多個Products ,每個Product使用外鍵(可能是Product.FormId )完全屬於一個Form

您的第一條語句將提取您的一個滿足某些要求的Forms ,如果沒有這樣的Form ,則為null。 在不檢查null返回值的情況下,您嘗試更改此FormProducts

問題是,可能有多個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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM