2013-04-30 93 views
0

我在其中一个环境中出现以下错误。这似乎发生在IIS重新启动时,但我们没有缩小细节来重现它。在SubSonic中创建查询对象时出现错误

A DataTable named 'PeoplePassword' already belongs to this DataSet. 
at System.Data.DataTableCollection.RegisterName(String name, String tbNamespace) 
at System.Data.DataTableCollection.BaseAdd(DataTable table) 
at System.Data.DataTableCollection.Add(DataTable table) 
at SubSonic.SqlDataProvider.GetTableSchema(String tableName, TableType tableType) 
at SubSonic.DataService.GetSchema(String tableName, String providerName, TableType tableType) 
at SubSonic.DataService.GetTableSchema(String tableName, String providerName) 
at SubSonic.Query..ctor(String tableName) 
at Wad.Elbert.Data.Enrollment.FetchByUserId(Int32 userId) 

基于stacktrace,我相信错误发生在创建查询对象的方法的第二行。 请让我知道是否有其他人有这个问题。 谢谢!

该函数的代码是:

 public static List<Enrollment> FetchByUserId(int userId) 
    { 
     List<Enrollment> enrollments = new List<Enrollment>(); 
     SubSonic.Query query = new SubSonic.Query("Enrollment"); 
     query.SelectList = "userid, prompt, response, validationRegex, validationMessage, responseType, enrollmentSource"; 
     query.QueryType = SubSonic.QueryType.Select; 
     query.AddWhere("userId", userId); 
     DataSet dataset = query.ExecuteDataSet(); 
     if (dataset != null && 
      dataset.Tables.Count > 0) 
     { 
      foreach (DataRow dr in dataset.Tables[0].Rows) 
      { 
       enrollments.Add(new Enrollment((int)dr["userId"], dr["prompt"].ToString(), dr["response"].ToString(), dr["validationRegex"] != null ? dr["validationRegex"].ToString() : string.Empty, dr["validationMessage"] != null ? dr["validationMessage"].ToString() : string.Empty, (int)dr["responseType"], (int)dr["enrollmentSource"])); 
      } 
     } 
     return enrollments; 
    } 
+0

没有答案,但你使用的是github最新的2.x版本吗? – 2013-04-30 22:43:29

回答

0

这是一个线程问题。

在第一次调用SubSonic.DataService.GetTableSchema(...)时子音加载它的模式,但这不是线程安全的。

让我用一个小例子

private static Dictionary<string, DriveInfo> drives = new Dictionary<string, DriveInfo>; 

private static DriveInfo GetDrive(string name) 
{ 
    if (drives.Count == 0) 
    { 
     Thread.Sleep(10000); // fake delay 
     foreach(var drive in DriveInfo.GetDrives) 
      drives.Add(drive.Name, drive); 
    } 
    if (drives.ContainsKey(name)) 
     return drives[name]; 
    return null; 
} 

这很好地解释了什么发生在这个方法中,在第一次调用该词典是空的
如果是这样的方法将预装所有驱动器的情况下证明这一点。

对于每次调用,返回请求的驱动器(或null)。

但是如果您在启动后直接启动两次该方法会发生什么?然后这两个执行尝试加载字典中的驱动器。第一个添加一个驱动器胜出第二个会抛出一个ArgumentException(元素已经存在)。

初始预加载后,一切工作正常。

长话短说,你有两个选择。

  1. 修改亚音速源以使SubSonic.DataService.GetTableSchema(...)线程安全。 http://msdn.microsoft.com/de-de/library/c5kehkcz(v=vs.80).aspx

  2. “Warmup”亚音速在接受请求之前。实现这一目标的技术取决于您的应用程序设计。对于ASP.NET你有一个Application_Start方法,你的应用程序生命周期中只执行一次 http://msdn.microsoft.com/en-us/library/ms178473(v=vs.100).aspx

所以你基本上可以把

var count = new SubSonic.Query("Enrollment").GetRecordCount(); 

的方法来强制亚音速到初始化表模式本身。