【问题标题】:LINQ to SQL Repository pattern auto increment problemLINQ to SQL Repository 模式自动增量问题
【发布时间】:2011-08-19 05:44:42
【问题描述】:

我有一个奇怪的问题,我正试图弄清楚是我的代码还是数据库搞砸了。我有一个表 WebClienteLogin ,它有一个属性 Id(主键,自动增量)。当用户在网站上注册时,我正在插入新记录。

昨天早上最后一个注册用户的id值达到了9000左右,下午开始奇怪地跳跃,所以下一个用户的id是1200,25000......,它达到了290000。然而,今天它继续正常(增加1)。从统计数据来看,当有大量用户同时注册时会发生这种情况。

使用的技术:SQL Server 2008 R2、ASP.NET MVC2、.NET 3.5

我正在使用带有 LINQ 的存储库模式。这是我的一个存储库的实现。

public SQLWebClientLoginRepository(string connectionString)
{
                dataContext = new DataContext(connectionString);
                tabla = dataContext.GetTable<WebClientLogin>(); 
}


public bool Save(WebClientLogin user)
            {
                bool success = true;            

                try
                {
                    if (user.Id == 0)
                    {
                        tabla.InsertOnSubmit(user);
                    }
                    else if (tabla.GetOriginalEntityState(user) == null)
                    {
                        tabla.Attach(user);
                        tabla.Context.Refresh(RefreshMode.KeepCurrentValues, user);
                    }
                    tabla.Context.SubmitChanges();  
                }
                catch
                {
                    ......
                }

                return success;
     }

用户还附加了其他对象,因此它插入到两个表中,并且 LINQ 将其包装到事务中。

  var user = new WebClientLogin();
  // assigning other properties
  user.WebClient = new WebClient { // setting propeties }

  webClientLoginRepository.Save(user)

在日志中我得到异常:

试图删除一个 WebClientLogin 和 WebCLient 之间的关系 但是,关系的外键之一 (WebClient.WebCLientLogin_id) 不能设置为 null。”异常

我不知道为什么要这样做!有没有人经历过类似的事情?

【问题讨论】:

    标签: c# sql-server linq-to-sql asp.net-mvc-2 repository-pattern


    【解决方案1】:

    启动数据库状态:

    WebClientLogin
    ID = 900
    
    WebClient
    ID = 1, WebClientLogin_Id = 900
    

    在修改前的内存中:

    WebClientLogin
    ID = 900
    
    WebClient
    ID = 1, WebClientLogin_Id = 900, WebClientLogin = that instance with 900
    

    检查 WebClientLogin 的 WebClient 属性。 SubmitChanges 时在内存中:

    WebClientLogin
    ID = 900
    
    WebClient (original instance)
    ID = 1, WebClientLogin_Id = 900, WebClientLogin = null
    
    WebClient  (new instance!)
    ID = 0, WebClientLogin_Id = 900, WebClientLogin = that instance with 900
    

    尝试更改数据库:

    WebClientLogin (no change)
    ID = 900
    
    WebClient (new row, inserted)
    ID = 2, WebClientLogin_Id = 900
    
    WebClient (original row, updated)
    ID = 1, WebClientLogin_Id = 900 -> null  (error, rollback transaction)
    

    【讨论】:

    • 感谢您的回复。一切似乎都是正确的,并且正确分配了 WebClientLogin 属性。这是一个非常困难的情况,因为它只发生在用户“轰炸”注册表时,所以我实际上无法调试它。我将不得不写入记录每个正在注册的用户的属性值。
    • 在这种情况下,我实际上会记录所有内容。您还应该为您的应用构建压力测试,并针对您的本地调试代码运行该测试,以模拟注册轰炸并重现问题。
    【解决方案2】:

    我稍微修改了存储库,但似乎解决了这个问题,但现在我有另一个问题。

    public bool Save(WebClientLogin login, WebClient client)
            {
                var created = false;
    
                using (var transaction = new TransactionScope())
                {
                    try
                    {
         // insert WebClientLogin first
                        tablalogin.InsertOnSubmit(login);
                        dataContext.SubmitChanges();
    
         // insert WebClient second
                        client.WebClientLogin_id = login.Id;
                        tablacliente.InsertOnSubmit(client);
    
                        dataContext.SubmitChanges();
                        created = true;
                        transaction.Complete();
                    }
                    catch (Exception ex)
                    {
                        //
                    }
                }
                return created;
            }
    

    当有大量用户时,我只插入 WebClientLogin 而没有插入 WebClient 我得到了这个例外:

    Internal .Net Framework Data Provider error 60
    

    【讨论】:

    • 您不应该像那样直接进行 ID 管理。查看 WebClient 的 WebClientLogin 属性并查看自动生成的属性如何管理 ID。应该能够对 SubmitChanges 进行一次调用。
    • 我知道这一点。这就是我之前所做的,因为 SubmitChanges() 将整个事情包装到事务中,但是当我这样做时,只有在有大量用户同时注册的情况下,我才会得到 Id 的那些有趣的跳跃。否则就好了。上面的代码似乎解决了这个问题。但是,有时无法使用 TransactionScope 对两个表执行 INSERT。所以我最终只将一些用户输入到 1 个表中。这玩意儿我快疯了!
    【解决方案3】:

    嗯....整个应用程序提供了大量其他奇怪的异常。所以我们拜访了我们的主人,我们发现了它的原因。主机配置了 3 台专用 Web 服务器和 1 台数据库服务器。他们为 Web 服务器配置了负载均衡器和 dfs。他们关闭了三分之二的服务器并进行了压力测试。从那时起,没有错误/异常或错误的交易。好像是服务器问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多