LINQ-to-SQL +一对多+数据绑定删除

我使用LINQ-to-SQL从具有一对多关系的两个表的数据库加载数据(一个Recipe有许多成分)。

我加载一个Recipe,LINQ将Ingredient对象检索到一个绑定到ListBox的EntitySet中。

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

我通过在DBML文件中添加’DeleteOnNull =“true”’,使用众所周知的解决方案解决了这个问题。 但添加此设置仅在我们删除从DB检索到的Ingredient对象时才会消除此问题。

问题在于在代码中创建的成分对象(添加到配方中)并添加到成分的EntitySet集合中,然后在调用SubmitUpdates之前删除。 然后,再次发生同样的exception。 当用户向其中添加成分,出错并从配方中删除配料时,通常会在新的未保存的配方上发生这种情况。 我将DeleteOnNull添加到DBML中的’Association Name =“Recipe_Ingredient”’行。

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

try { // Needed for existing records, but will fail for new records yourLINQDataContext.Ingredients.DeleteOnSubmit(ingredient); } catch (Exception) { // Swallow } yourRecipeObject.Ingredients.Remove(ingredient); 

几天前,当我问“ 如何使用确定/取消按钮为数据绑定WPF对话框设计支持数据类型? ”时,您似乎正在寻找我自己正在寻找的东西。

答案是Paul Stovell的一篇有趣的post,描述了一个用于Linq到Sql 的示例IEditable适配器 。 这将允许您以通用方式创建所需的“应用/取消”语义,而无需通过完整的自定义编写层完全与基础ORm生成的类分离。

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

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

 // 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,从而导致约束违规和exception。

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

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

你需要将保存代码与GUI中的事件分离,看起来你有点急于在尘埃落定之前将内容保存到数据库并且你正在排队并从数据库中删除从未到达过的数据库首先,最好是在用户“提交”他们的更改时确定一个点,并且在那一刻,处理GUI的完整条件 – 这将为您节省一堆意大利面条代码。

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

你有没有将一个文本编写器连接到你的DataContext.Log,看看在你获得你的exeception之前生成了什么类型的SQL?

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

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

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

我发现只有在保存之前将子对象样式属性设置为另一个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对象没有任何关系。 似乎只需设置新实体的任何对象属性就会触发问题。

NB。 示例1在保存方面工作正常,如果在保存之前删除新实体,则只会导致问题。

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

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