2013-04-30 91 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(); 

的方法來強制亞音速到初始化表模式本身。