代码之家  ›  专栏  ›  技术社区  ›  Mayo

ASP.NET MVC中的Linq to SQL导致DuplicateKeyException

  •  3
  • Mayo  · 技术社区  · 15 年前

    我以体育用品商店为例 Pro ASP.NET MVC Framework 我得到了一个与Linq相关的异常,我不知道。完整的代码可以在网站上找到,但这里有一个片段来传达这个问题。

    private Table<Product> productsTable;
    // ...
    public void SaveProduct(Product product) {
      if (product.ProductID == 0)
        productsTable.InsertOnSubmit(product);
      else {
        productsTable.Attach(product);
        productsTable.Context.Refresh(RefreshMode.KeepCurrentValues, product);
      }
      productsTable.Context.SubmitChanges();
    }
    

    在用户界面中,我更新一个已有的产品,然后单击保存,控制器通过调用save product(product)来处理日志,其中product通过参数传递。在附加的产品上抛出重复的eyexception。在调试器中,产品参数已初始化,其ID为2。

    我不希望有确切的答案,但我希望有人能给我一些提示,告诉我在哪里可以解决这个问题。

    更新 :下面的代码可以工作,但我仍然希望上面的attach方法可以工作。

    public void SaveProduct(Product product) {
      if (product.ProductID == 0)
        productsTable.InsertOnSubmit(product);
      else {
        Product p2 = productsTable.Single(em => em.ProductID == product.ProductID);
        p2.Name = product.Name;
        p2.Description = product.Description;
        p2.Price = product.Price;
        p2.Category = product.Category;
      }
      productsTable.Context.SubmitChanges();
    }
    
    4 回复  |  直到 14 年前
        1
  •  1
  •   griegs    15 年前

    我可能错了,但我认为你唯一能得到这个的时间是你填充一个对象然后试图保存它。如果您正在更新一个现有的对象,那么我认为您需要首先加载它,使用updateModel之类的工具进行更改,然后保存。

    L2S知道它正在保存的对象已经被加载,它是一个更新操作,而不是一个插入操作。

    这对你的问题有意义吗?

        2
  •  0
  •   Mayo    15 年前

    我想出来了,但我要给格里格一个答案,因为他让我走上正轨。这里是以防有人打它。我使用了SQL事件探查器,注意到在保存时没有看到任何对数据库的命中,甚至没有选择任何记录。

    我最终在web.config中发现了一个很小的打字错误,由于行的不同,我没有在beyond-compare中看到。

    <component id="ProdsRepository" service="DomainModel.Abstract.IProductsRepository, DomainModel" type="DomainModel.Concrete.SqlProductsRepository, DomainModel" lifesyle="PerWebRequest">
    

    VS

    <component id="ProdsRepository" service="DomainModel.Abstract.IProductsRepository, DomainModel" type="DomainModel.Concrete.SqlProductsRepository, DomainModel" lifestyle="PerWebRequest">
    

    如果你没有发现它,生活方式属性就拼错了。存储库正在进行持久化,因此数据已经按照griegs的建议进行了加载。

        3
  •  0
  •   name1ess0ne    15 年前

    你可以改变 更新检查 对象中的属性 从未 (它与工作相关联)或使用类似的东西:

    public void SaveProduct(Product product) 
    {
      if (product.ProductID == 0)
        productsTable.InsertOnSubmit(product);
      else 
      {
       Product old = productsTable.Single(em => em.ProductID == product.ProductID);
       ApplyChanges(ref old, product);
      }
      productsTable.Context.SubmitChanges();
    }
    
    private static void ApplyChanges<T>(ref T Original, T Changes)
    {
        Type OriginalType = typeof(T);
    
        PropertyInfo[] Info = OriginalType.GetProperties();
    
        foreach (PropertyInfo PI in Info)
        {
            foreach (Attribute attr in Attribute.GetCustomAttributes(PI)) 
            {
                // Check for the Column attribute.
                if (attr.GetType() == typeof(System.Data.Linq.Mapping.ColumnAttribute))
                {
                    if(((attr as System.Data.Linq.Mapping.ColumnAttribute).IsDbGenerated == false) && PI.CanWrite)
                    {
                        PI.SetValue(Original, PI.GetValue(Changes, null), null);
                    }
                    break;
                }
            }
        }
     }
    
        4
  •  0
  •   Stephen Hosking    14 年前

    我在视图中有productID(键)时也得到了这个,因为我允许vs使用“view content:edit”选项生成视图。(书中的代码删除了productID,但我发现最好的学习方法是进行一点实验——尽管这个错误花费了几个小时,但还是值得的)。

    顺便说一句,好书!