Обновление Entity Framework Многие-ко-многим без создания дубликатов?

#c# #asp.net-mvc #angularjs #entity-framework

#c# #asp.net-mvc #angularjs #entity-framework

Вопрос:

Я использую Entity Framework (сначала код) для создания базы данных, часть которой содержит две сущности с отношением «многие-ко-многим». Вот их код:

 public class Product
{
    [Key]
    public int ProductId { get; set; }

    [MaxLength(50)]
    public string CUSIP { get; set; }

    [MaxLength(50)]
    public string SEDOL { get; set; }

    [MaxLength(50)]
    public string BUID { get; set; }

    [MaxLength(50)]
    public string Key { get; set; }

    [Required]
    public bool Track { get; set; }

    [InverseProperty("Products")]
    [ForeignKey("ProductListId")]
    public virtual List<ProductList> ProductLists { get; set; }

    public override string ToString()
    {
        return String.Format("PRODUCT[ ProductId: {0}, CUSIP: {1}, SEDOL: {2}, BUID: {3}, Key: {4}, Track: {5}, ProductLists: {6} ]",
                            ProductId,
                            CUSIP,
                            SEDOL,
                            BUID,
                            Key,
                            Track,
                            (ProductLists != null ? "" ProductLists.Count : "null"));
    }
}

public class ProductList
{
    [Key]
    public int ProductListId { get; set; }

    [Required]
    [MaxLength(50)]
    public string Name { get; set; }

    [InverseProperty("ProductLists")]
    [ForeignKey("ProductId")]
    public virtual List<Product> Products { get; set; }

    public override string ToString()
    {
        return String.Format("PRODUCT-LIST[ ProductListId: {0}, Name: {1}, Products: {2} ]",
                            ProductListId, 
                            Name,
                            (Products != null ? ""   Products.Count : "null"));
    }
}
 

В моем репозитории я пытаюсь написать метод обновления для продукта, такой, чтобы изменение логического значения отслеживания или добавление / удаление его из списка продуктов сохранялось в базе данных. Я использую AngularJS и asp.net-MVC для остальной части моего проекта, поэтому вот метод обновления в классе ProductsController:

     public void Put(int id, [FromBody] Product product)
    {
        _repo.UpdateProduct(id, product);
        _repo.Save();
    }
 

Поскольку это вызывается из AngularJS, объект product инициализируется из объекта JS.

И, наконец, вот updateProduct метод в репозитории:

     public bool UpdateProduct(int id, Models.Product product)
    {
        if (product != null) System.Diagnostics.Debug.WriteLine("UpdateProduct() ["   id   "]n"   product.ToString());

        if (id == 0) return AddProduct(product);

        try
        {
            Product ctxProduct = GetProduct(id);
            if (ctxProduct != null amp;amp; product != null)
            {
                ctxProduct.CUSIP = product.CUSIP;
                ctxProduct.SEDOL = product.SEDOL;
                ctxProduct.BUID = product.BUID;
                ctxProduct.Key = product.Key;
                ctxProduct.Track = product.Track;

                /*ctxProduct.ProductLists = new List<ProductList>();
                for (int i = 0; i < product.ProductLists.Count; i  )
                {
                    ctxProduct.ProductLists.Add((product.ProductLists[i].ProductListId == 0)
                                                ? product.ProductLists[i]
                                                : GetProductListIncludingProducts(product.ProductLists[i].ProductListId));

                }*/
                return true;
            }
            return false;
        }
        catch (Exception e)
        {
            System.Diagnostics.Debug.WriteLine(e.Message   "n ----- "   e.InnerException);
            return false;
        }
    }
 

Прямо сейчас раздел, который должен обновлять отношения ProductList, закомментирован. Пока это так, я могу обновить любое другое поле в продукте, и оно будет работать так, как ожидалось.

Если я раскомментирую этот раздел, код создаст повторяющиеся списки продуктов в базе данных, а также дубликаты всех продуктов, содержащихся в этих списках.

Наконец, если я заменяю GetProductListIncludingProducts(product.ProductLists[i].ProductListId) на GetProductList(product.ProductLists[i].ProductListId) , я получаю следующую ошибку из _repo.Save() :

 System.Data.SqlClient.SqlException: Violation of PRIMARY KEY constraint 'PK_dbo.ProductListProducts'. Cannot insert duplicate key in object 'dbo.ProductListProducts'
 

GetProductListIncludingProducts() просто добавляет .Включить («Продукты») в его вызов контекста.

Я хотел бы, чтобы метод обновления просто перенастроил отношения «многие ко многим» без сбоев или создания большого количества повторяющихся данных.

Ответ №1:

Это заняло некоторое время, но я, наконец, понял это. Оказывается, проблема была в моем форматере WebAPI. В моем коде по умолчанию использовался XMLMediaFormatter — когда я ожидал, что он будет использовать мой JsonMediaFormatter, который я настроил для обработки отслеживания ссылок. На случай, если это кому-нибудь поможет, вот мой окончательный метод UpdateProduct, который работает с JsonMediaFormatter:

     public bool UpdateProduct(int id, Product product)
    {
        if (product != null) System.Diagnostics.Debug.WriteLine("UpdateProduct() ["   id   "] "   product.ToString());

        if (id == 0) return AddProduct(product);

        try
        {
            Product ctxProduct = GetProductIncludingProductLists(id);

            if (ctxProduct != null amp;amp; product != null)
            {
                ctxProduct.CUSIP = product.CUSIP;
                ctxProduct.SEDOL = product.SEDOL;
                ctxProduct.BUID = product.BUID;
                ctxProduct.Key = product.Key;
                ctxProduct.Track = product.Track;

                ctxProduct.ProductLists = new List<ProductList>();
                foreach (ProductList pl in product.ProductLists)
                    ctxProduct.ProductLists.Add(pl.ProductListId == 0 
                                                ? pl 
                                                : GetProductList(pl.ProductListId));
                return true;
            }
            return false;
        }
        catch (Exception e)
        {
            System.Diagnostics.Debug.WriteLine("Update Product Error: "   e.Message   "nInner: "   e.InnerException);
            return false;
        }
    }