0

私たちの環境の 1 つで次のエラーが発生しています。IIS の再起動時に発生するようですが、詳細を絞り込んで再現していません。

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) 

スタックトレースに基づいて、クエリ オブジェクトの作成中にメソッドの 2 行目でエラーが発生していると思われます。他の誰かがこの問題を抱えている場合はお知らせください。ありがとう!

関数のコードは次のとおりです。

        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;
    }
4

1 に答える 1

0

これはスレッドの問題です。

Subsonic は最初の呼び出しでそのスキーマをロードしますが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) が返されます。

しかし、開始直後にメソッドを 2 回起動するとどうなるでしょうか。次に、両方の実行でディクショナリにドライブをロードしようとします。最初にドライブを追加すると、2 番目に ArgumentException がスローされます (要素は既に存在します)。

最初のプリロードの後、すべてが正常に機能します。

簡単に言えば、2 つの選択肢があります。

  1. サブソニック ソースを変更して、SubSonic.DataService.GetTableSchema(...)スレッド セーフにします。 http://msdn.microsoft.com/de-de/library/c5kehkcz(v=vs.80).aspx

  2. リクエストを受け入れる前に亜音速で「ウォームアップ」します。これを達成するためのテクニックは、アプリケーションの設計によって異なります。ASP.NET の場合Application_Start、アプリケーションのライフサイクル中に一度だけ実行されるメソッドがあります http://msdn.microsoft.com/en-us/library/ms178473(v=vs.100).aspx

したがって、基本的には

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

subsonic にテーブル スキーマ自体を強制的に初期化させる方法で。

于 2013-05-29T12:55:15.873 に答える