【问题标题】:LINQ-to-SQL + One-to-Many + DataBinding deletingLINQ-to-SQL + 一对多 + DataBinding 删除
【发布时间】:2008-12-21 18:19:45
【问题描述】:

我使用 LINQ-to-SQL 从一个数据库中加载数据,该数据库有两个以一对多关系存在的表(一个配方有很多成分)。

我加载一个食谱,LINQ 将成分对象检索到一个绑定到列表框的实体集中。

如果我想从食谱中删除一些成分,我会收到“尝试删除食谱和成分之间的关​​系。但是,不能将关系的外键之一 (Ingredient.RecipeID) 设置为空。

我通过将“DeleteOnNull="true"' 添加到 DBML 文件中,使用众所周知的解决方案解决了这个问题。但添加此设置只会在我们删除从数据库中检索到的成分对象时解决问题。

问题在于在代码中创建的成分对象(添加到配方中)并添加到成分的 EntitySet 集合中,然后在调用 SubmitUpdates 之前删除。然后,同样的异常再次发生。这通常发生在新的、未保存的食谱上,当用户向其中添加成分、犯错误并从食谱中删除成分时。我将 DeleteOnNull 添加到 DBML 中的两个 'Association Name="Recipe_Ingredient"' 行。

我应该如何删除这些对象?我目前看到的唯一解决方案是,我会将配料加载到不在 DataContext 下的集合中,然后在保存时,从配方中删除所有配料,然后从该缓存中再次添加......

【问题讨论】:

  • 你说的是 Linq-SQl 还是 Linq to Entities??
  • 当您添加/删除成分对象时,您的新 Reciepe 对象是否属于 DataContext?
  • 否(当配方是新配方时)和是(当它是现有配方时,从数据库中检索并添加成分)。

标签: c# linq-to-sql entityset


【解决方案1】:
        try
        {
            // Needed for existing records, but will fail for new records
            yourLINQDataContext.Ingredients.DeleteOnSubmit(ingredient);
        }
        catch (Exception)
        {
            // Swallow
        }

        yourRecipeObject.Ingredients.Remove(ingredient);

【讨论】:

  • 我已经实现了这个确切的代码:) 如前所述,它适用于从内存和数据库中删除的成分记录(删除加载配方时从数据库加载的成分)。它不适用于刚刚在内存中创建和删除的新的未提交的。
  • 上面的代码处理刚刚在内存中创建和删除的新的未提交的代码(它不是示例代码 - 我从一个实时生产应用程序中复制并粘贴了代码并更改了类型的名称和变量)。您最初创建成分时是否调用了 InsertOnSubmit?
  • 你做到了!我确实将新的成分对象添加到了 Recipe 对象的 EntitySet 集合中,但没有调用 InsertOnSubmit,因为它似乎什么也没做。但是你的建议解决了这个问题。非常感谢!
【解决方案2】:

您似乎在寻找几天前我问“How do I design backing data types for a databound WPF dialog with Ok/Cancel buttons?”时我一直在寻找的东西。

答案是来自 Paul Stovell 的一篇有趣的帖子,他描述了 Linq to Sql 的 a sample IEditable adapter。这将使您能够以通用的方式创建所需的“应用/取消”语义,而无需通过完整的自定义编写层将自己与底层 ORm 生成的类完全分离。

总的来说,这是一个非常巧妙的技巧,它基本上可以让你回避你现在正在解决的问题。 :)

另一方面,我很好奇为什么你的配方与成分的关系是 1:n 而不是 m:n。是为了简单吗?我在很多食谱中都使用大蒜。 :)

【讨论】:

    【解决方案3】:
    // Create new entities
    Cart c = new Cart();
    CartEntry ce = new CartEntry();
    ce.Cart = c;
    
    // Delete the entry
    c.CartEntries.Remove(ce);
    dc.Cartentries.Attach(ce);
    dc.CartEntries.DeleteOnSubmit(ce);
    
    // Insert the cart into database
    dc.Carts.InsertOnSubmit(c);
    dc.SubmitChanges();
    

    问题说明:c 和 ce 这两个实体都与数据上下文无关 - 它们没有被跟踪。 EntitySet.Remove()(第一个删除行)只删除 c 和 ce 之间的关系。虽然 c 可以在没有关联的购物车条目的情况下存在,但由于外键约束, ce 不能在没有关联的购物车的情况下存在。在向数据库提交更改时,断开连接的ce也被处理,导致违反约束和异常。

    为了摆脱未跟踪和断开连接的购物车条目,您需要将其附加到您的数据上下文(使其被跟踪),然后将其标记为在提交时删除。在您提交更改的那一刻,购物车条目将被正确删除,不会导致异常。

    有关该问题的更多详细信息,请查看以下内容: http://msdn.microsoft.com/en-us/library/bb546187%28v=VS.100%29.aspx

    【讨论】:

      【解决方案4】:

      您需要将保存代码与 GUI 中的事件分离,您似乎有点急于在尘埃落定之前将内容保存到数据库中,并且您正在排队并从数据库中删除那些从一开始就没有到达那里,最好能确定用户“提交”他们的更改的时间点,并且在那一刻处理 GUI 的全部条件 - 这将为您节省一堆意大利面条代码.

      我也很想知道您的实体是否有自动编号 ID,或者您是否正在使用其他一些 ID 机制。您可能正在向数据库发送 DELETE 以获取尚未提交的成分记录,如果这些记录包含 NULL ID,我认为 linq 可能会变得讨厌。

      您是否将文本编写器连接到 DataContext.Log 以查看在您收到异常之前生成了哪些类型的 SQL?

      【讨论】:

      • 澄清一点:我(1)将数据从数据库拉到内存集合。 (2) 将该集合绑定到 GUI。 (3) 内存集合中数据的增、改、删。 (4) 当用户按下 Save 时,通过 LINQ 提交回 DB。问题在于创建、添加、删除(并且从未提交)的集合成员
      【解决方案5】:

      感谢您的回答,我会检查帖子,看看我能做些什么。我必须说我很惊讶甚至看到这个问题发生,对我来说似乎很自然可以将记录添加到 LINQ 提供的数据“缓存”中,然后决定删除其中一些然后提交。更改跟踪应该能够处理这个问题。我刚开始使用 LINQ,所以我可能在代码的某个地方犯了一个愚蠢的错误(不会是第一个)。

      另一方面:你说得对,大蒜可以属于许多食谱(不是我的鸡尾酒食谱想的!)。我实际上是用文章对象/表来建模的。但是对于食谱,您需要数量。因此,在我的模型中,您有一个包含 1:n 成分的食谱,每个成分都有一个数量、一个指向文章的 1:1 链接(其中有一个名称、一个酒精含量和一些用于建立可互换层次结构的数据)和一个1:1 链接到一个单位(使数量有意义)。 所以从某种意义上说,成分表在食谱和文章之间建立了 M:N 关系,同时为每个单独的链接对添加了一些额外的信息。

      【讨论】:

        【解决方案6】:

        我遇到了完全相同的问题。我有一个父/子层次结构,当添加和删除子实体而不保存到数据库时,我收到“尝试删除关系”异常。

        我发现只有在保存之前将子对象的对象样式属性设置为另一个 linq-sql 实体时才会出现此问题。例如

        1.这会产生错误

         RetailAccountCustomerCard racc = new RetailAccountCustomerCard();
        
         Card addedCard = _idc.Cards.Where(c => c.CardId == card.CardId).ToList().First();
        
         racc.Card = addedCard;
        
         this.CurrentCustomer.RetailAccountCardsBindingList.Add(racc); 
        
         // Some code triggered by the user before saving to the db
        
         CurrentCustomer.RetailAccountCardsBindingList.Remove(racc);
        

        2。这不会产生错误

         RetailAccountCustomerCard racc = new RetailAccountCustomerCard();
        
         racc.CardId = card.CardId;  // note that I have set the Id property not the object
        
         this.CurrentCustomer.RetailAccountCardsBindingList.Add(racc); 
        
        
         // Some code triggered by the user before saving to the db
        
         CurrentCustomer.RetailAccountCardsBindingList.Remove(racc);
        

        奇怪的是,1. 中出现的错误指定问题与关系有关,即 RetailAccountCustomerCard 的 RetailAccountCustomerId 属性。 它与我添加的 Card 对象无关。似乎只需设置新实体的 any 对象属性就会触发问题。

        注意。示例 1 在保存方面效果很好,只有在保存之前删除新实体才会导致问题。

        【讨论】:

        • 调用 DataContext.GetChanges() 似乎可以解决案例 1 中的问题。您也不需要使用第一种方法设置关系。
        • @NeilBarnwell 你找到解决方案了吗?
        • @Roland 我从来没有,没有。如果你到达黑暗之塔,请回来告诉我们,嗯? ;)
        • @NeilBarnwell 感谢您的反应。看来我自己找到了解决办法:social.msdn.microsoft.com/Forums/en/linqtosql/thread/…漫长的白天和愉快的夜晚……
        【解决方案7】:

        我遇到了类似的问题,作为一种解决方法,我需要调用 DataContext.GetChanges(),然后一切似乎又开始流行了 :)

        您可能会遇到另一个问题,即您绑定到列而不是实体属性,因此引用集合没有更新(其他人已经声明,但强制执行该事实)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-10-07
          • 2023-04-05
          • 1970-01-01
          • 2020-10-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多