LINQ To SQL忽略唯一约束异常并继续

时间:2010-03-18 14:49:38

标签: c# sql-server linq-to-sql caching

我在名为Users

的数据库中有一个表
Users
------
ID (PK, Identity)
Username (Unique Index)

我在Username表上设置了一个唯一索引以防止重复。然后,我将通过集合枚举并在数据库中为每个项目创建新用户。

我想要做的只是插入一个新用户并在违反唯一键约束时忽略该异常(因为在这种情况下它显然是重复记录)。这是为了避免必须制作哪里不存在类型的查询。

首先,这会更高效还是我的插入代码应该检查重复项?我更多地了解具有该逻辑的数据库,因为这可以防止任何其他类型的客户端插入重复数据。

我的另一个问题与LINQ To SQL有关。我有以下代码:

public class TestRepo
{
    DatabaseDataContext database = new DatabaseDataContext();

    public void Add(string username)
    {
        database.Users.InsertOnSubmit(new User() { Username = username });
    }

    public void Save()
    {
        database.SubmitChanges();
    }
}

然后我迭代一个集合并插入新用户,忽略任何异常:

TestRepo repo = new TestRepo();

foreach (var name in new string[] { "Tim", "Bob", "John" })
{
    try
    {
        repo.Add(name);
        repo.Save();
    }
    catch {  }
}

第一次运行时,我在表中有三个用户。如果我删除第二个并再次运行此代码,则不会插入任何内容。我期望第一个插入失败,异常,第二个插入成功(因为我刚从数据库中删除该项),第三个插入失败。

似乎正在发生的事情是,一旦抛出SqlException(即使循环继续迭代),所有下一次插入都会失败 - 即使表中没有可能导致唯一违规的行。 / p>

任何人都能解释一下吗?

P.S。我能找到的唯一解决方法是每次在插入之前实例化repo,然后它完全按照例外工作 - 表明它与LINQ To SQL DataContext有关。

感谢。

4 个答案:

答案 0 :(得分:1)

在第二次插入时,dataContext将再次尝试插入第一个对象,因为它位于此dataContext的标识映射中(您希望插入'Tim'仍然未决 - 在第一次捕获后)。

在第一个循环中,您插入'Tim' 第二个'蒂姆'和'鲍勃' 在第三'蒂姆','鲍勃'和'约翰' 所以你不是只在第二个循环中插入'Bob',这就是失败的原因。

您可以尝试从cach中的DataContext中删除失败的名称,但无论如何,在一个数据上下文中多次提交都是非常糟糕的主意(我被烧毁了)。

答案 1 :(得分:0)

尝试在测试运行之间调用DataContext上的DataContext.Refresh

我认为你正忙于Linq-to-Sql的内部缓存,这就是重新创建DataContext作为解决方法的原因,当你新建DataContext时,新对象的缓存将为空。

答案 2 :(得分:0)

你应该使用try catch技巧检查是否存在。

foreach (var name in new string[] { "Tim", "Bob", "John" })
{
    var u = from users in db.Users
            where users.username == name
            select users;

    if (u.Count() == 0)
    {
       User user = new User();
       user.name = name;
       db.Users.InsertOnSubmit(user);
       db.SubmitChanges(System.Data.Linq.ConflictMode.ContinueOnConflict);
    }
}

答案 3 :(得分:0)

很难说你的方法是否“效率更高”。这取决于您获得重复帐户的频率。如果您的费率非常高,那么您就会失去速度,因为处理异常可能需要更多时间,而不是检查是否存在记录。

如果要最大化速度,请创建一个存储过程以检查并插入(如果它不在数据库中)。