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();

SchoolASchoolB 将因为上面的 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 时,如果其他列没有更改,如何避免设置某些列?

为啥 Linq-to-sql 错误地删除了我的联合中的字段?

如果不支持包含,您如何在 LINQ to Entities(实体框架)中执行 SQL 样式的“IN”语句?

SQL to LINQ 工具 [关闭]

Linq to SQL VS 实体框架