Linq to sql - 删除,如果失败继续
Posted
技术标签:
【中文标题】Linq to sql - 删除,如果失败继续【英文标题】:Linq to sql - delete and if fails continue 【发布时间】:2011-08-30 14:44:20 【问题描述】:如果我有这样的表:
StudentId | ... | SchoolId
___________|_____|__________
1 | ... | SchoolA
2 | ... | SchoolA
3 | ... | SchoolB
...
我想删除从 schoolA 到 schoolZ 的学校列表(使用 LINQ-to-SQL):
foreach(School s in schools)
db.Schools.DeleteOnSubmit(s);
db.submitChanges();
SchoolA
和 SchoolB
将因为上面的 FK 引用而失败
如何继续并删除所有其他学校,丢弃发生异常的学校?
【问题讨论】:
您应该始终在循环之外保持对SubmitChanges()
的调用。上下文会累积变化并可以批量发送。
忘了说,SchoolId 可以有更多对更多表的 FK 引用,所以检查它们不是一个选项
【参考方案1】:
仅包括没有学生的学校:
var schoolsToDelete = schools.Where(x => !x.Students.Any());
db.Schools.DeleteAllOnSubmit(schoolsToDelete);
db.submitChanges();
【讨论】:
【参考方案2】:默认情况下,LINQ to SQL 在第一个错误时失败并回滚事务。如果您希望它继续处理它可以做的任何事情,您可以在 SubmitChanges 上传递 ConflictMode 重载以允许它继续运行。 “LINQ in Action” 中的以下示例尝试发出所有排队的更新,然后输出通过处理 ChangeConflictException 遇到的冲突。
try
context.SubmitChanges(ConflictMode.ContinueOnConflict);
catch (ChangeConflictException)
var exceptionDetail =
from conflict in context.ChangeConflicts
from member in conflict.MemberConflicts
select new
TableName = GetTableName(context, conflict.Object),
MemberName = member.Member.Name,
CurrentValue = member.CurrentValue.ToString(),
DatabaseValue = member.DatabaseValue.ToString(),
OriginalValue = member.OriginalValue.ToString()
;
exceptionDetail.Dump();
当然,积极主动并仅尝试删除 Mark Cidade 所证明的有效记录要好得多。
【讨论】:
但是在这种情况下,这是应该抛出的异常吗?在我的情况下,抛出的异常是 SqlException 并且冲突的数据库上下文集合是空的...... 请注意,此标志仅适用于 UPDATE 期间的 并发 冲突,不适用于 INSERT 的唯一约束违规。【参考方案3】:我同意 Mark Cidade 的观点,但我可以建议改进使用连接范围向数据库服务器发送单个请求。
【讨论】:
【参考方案4】:我同意马克的解决方案。如果您不想删除学校及其学生,可以使用:
foreach (School s in schools)
db.Students.DeleteAllOnSubmit(s.Students);
db.Schools.DeleteOnSubmit(s);
db.submitChanges();
这样你就满足了 FK 约束,所以不会抛出错误。
【讨论】:
【参考方案5】:找到一个简单的方法
foreach(School s in schools)
try
db.Schools.DeleteOnSubmit(s);
db.submitChanges();
catch(SqlException exp)
if(exp.Message.Contains("The DELETE statement conflicted with the REFERENCE constraint")) //just checking if is FK reference
db.Schools.InsertOnSubmit(s); //=)
else
throw;
【讨论】:
性能会很糟糕!您将为大型数据集抛出数千或数百万个异常,比较字符串并在循环中弄乱上下文! 并且消息已本地化。它不适用于其他语言的系统以上是关于Linq to sql - 删除,如果失败继续的主要内容,如果未能解决你的问题,请参考以下文章
在使用 Linq To SQL 时,如果其他列没有更改,如何避免设置某些列?
为啥 Linq-to-sql 错误地删除了我的联合中的字段?