简体   繁体   English

实体框架多对多更新而不创建重复项?

[英]Entity Framework Many-to-Many update without creating duplicates?

I am using Entity Framework (Code-First) to create a database, part of which contains two entities with a many-to-many relationship. 我正在使用实体框架(代码优先)创建数据库,该数据库的一部分包含两个具有多对多关系的实体。 Here is their code: 这是他们的代码:

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"));
    }
}

In my repository, I am attempting to write an update method for product, such that changing the tracking Boolean or adding/removing it from a productList will save to the database. 在我的存储库中,我正在尝试编写产品的更新方法,以便更改跟踪布尔值或从productList中添加/删除跟踪布尔值将保存到数据库中。 I am using AngularJS and asp.net-MVC for the rest of my project, so here is the update method in the productsController class: 我在项目的其余部分使用AngularJS和asp.net-MVC,所以这里是productsController类中的update方法:

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

Because this is called from AngularJS, the product object is initialized from a JS object. 由于这是从AngularJS调用的,因此产品对象是从JS对象初始化的。

And finally, here's the updateProduct method in the repository: 最后,这是存储库中的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 && 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;
        }
    }

Right now, the section that should update the productList relations is commented out. 现在,应该更新productList关系的部分已被注释掉。 While it's like this, I can update any other field in the product and it will work as expected. 就像这样,我可以更新产品中的任何其他字段,它将按预期工作。

If I uncomment this section, the code will create duplicate productLists in the database, as well as duplicates of all the products contained in those lists. 如果我取消注释本节,则代码将在数据库中创建重复的productList,以及这些列表中包含的所有产品的重复。

Lastly, if I replace GetProductListIncludingProducts(product.ProductLists[i].ProductListId) with GetProductList(product.ProductLists[i].ProductListId) , I get the following error from _repo.Save() : 最后,如果我用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() simply adds .Include("Products") in its call to the context. GetProductListIn includedProducts()只需在对上下文的调用中添加.Include(“ Products”)。

I would like to get the update method to simply readjust the many to many relationship without crashing or creating a lot of duplicate data. 我想要更新方法来简单地重新调整多对多关系,而不会崩溃或创建大量重复数据。

It took awhile but I finally figured it out. 花了一段时间,但我终于想通了。 Turns out the problem was with my WebAPI formatter. 原来问题出在我的WebAPI格式化程序上。 My code was defaulting to the XMLMediaFormatter - when I was expecting it to be using my JsonMediaFormatter that I set up to handle reference tracking. 我的代码默认为XMLMediaFormatter-当我期望它使用设置为处理引用跟踪的JsonMediaFormatter时。 In case it helps anybody, here is my final UpdateProduct method that works with the JsonMediaFormatter: 万一它对任何人都有帮助,这是我与JsonMediaFormatter一起使用的最终UpdateProduct方法:

    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 && 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;
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM