2009-06-17 29 views
7

Linqのテンポラリテーブル - 誰でもこれに問題がありますか?解決しようとして

Linq .Contains with large set causes TDS error

私は解決策に出くわしたと思う、と私はそれが問題にアプローチするコーシャー方法だかどうかを確認したいと思います。

(短い要約)SQLで生成された(完全にまたは少なくとも簡単に)レコードIDのリストに対してlinq-joinしたいと思います。これは大きなリストで、TDS RPC呼び出しの2100項目制限を超えて頻繁に吹いています。だから、私がSQLで行ったことは、一時テーブルでそれらをスローし、それを必要とするときにそれに参加しました。

私はLinqでも同じことをしました。私MyDB.dbmlファイルで

私が追加:

<Table Name="#temptab" Member="TempTabs"> 
    <Type Name="TempTab"> 
    <Column Name="recno" Type="System.Int32" DbType="Int NOT NULL" 
      IsPrimaryKey="true" CanBeNull="false" /> 
    </Type> 
</Table> 

がデザイナーを開く万全を期すために、私はMyDB.desginer.csファイルから引用されますが、それは、そこに必要なエントリを追加閉じる:

[Table(Name="#temptab")] 
    public partial class TempTab : INotifyPropertyChanging, INotifyPropertyChanged 
    { 

      private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty); 

      private int _recno; 

#region Extensibility Method Definitions 
partial void OnLoaded(); 
partial void OnValidate(System.Data.Linq.ChangeAction action); 
partial void OnCreated(); 
partial void OnrecnoChanging(int value); 
partial void OnrecnoChanged(); 
#endregion 

      public TempTab() 
      { 
        OnCreated(); 
      } 

      [Column(Storage="_recno", DbType="Int NOT NULL", IsPrimaryKey=true)] 
      public int recno 
      { 
        get 
        { 
          return this._recno; 
        } 
        set 
        { 
          if ((this._recno != value)) 
          { 
            this.OnrecnoChanging(value); 
            this.SendPropertyChanging(); 
            this._recno = value; 
            this.SendPropertyChanged("recno"); 
            this.OnrecnoChanged(); 
          } 
        } 
      } 

      public event PropertyChangingEventHandler PropertyChanging; 

      public event PropertyChangedEventHandler PropertyChanged; 

      protected virtual void SendPropertyChanging() 
      { 
        if ((this.PropertyChanging != null)) 
        { 
          this.PropertyChanging(this, emptyChangingEventArgs); 
        } 
      } 

      protected virtual void SendPropertyChanged(String propertyName) 
      { 
        if ((this.PropertyChanged != null)) 
        { 
          this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
        } 
      } 
    } 

次に、コード内のいくつかのことを巡ってジャグリングすることになりました。どこで正常に持っていたと思います:

MyDBDataContext mydb = new MyDBDataContext(); 

私は一時テーブルを作成するために、接続を使用することができるように、それは通常のSqlConnectionオブジェクトとの接続を共有するために取得しなければなりませんでした。その後、それはかなり使えるようです。

string connstring = "Data Source.... etc.."; 
SqlConnection conn = new SqlConnection(connstring); 
conn.Open(); 

SqlCommand cmd = new SqlCommand("create table #temptab " + 
           "(recno int primary key not null)", conn); 
cmd.ExecuteNonQuery(); 

MyDBDataContext mydb = new MyDBDataContext(conn); 
// Now insert some records (1 shown for example) 
TempTab tt = new TempTab(); 
tt.recno = 1; 
mydb.TempTabs.InsertOnSubmit(tt); 
mydb.SubmitChanges(); 

そして、それを使用して:

// Through normal SqlCommands, etc... 
cmd = new SqlCommand("select top 1 * from #temptab", conn); 
Object o = cmd.ExecuteScalar(); 

// Or through Linq 
var t = from tx in mydb.TempTabs 
     from v in mydb.v_BigTables 
     where tx.recno == v.recno 
     select tx; 

誰のLINQに参加するには、一時テーブルを使用するための汎用的なソリューションとして、このアプローチの問題を参照してくださいしていますか?

私の問題をすばらしく解決しました。今はLinqで直接.Contains()を使う必要がなくなりました。

ポストスクリプト: 私が持っている一つの問題は、(1が書き込み/読み出しであるので、他がどこにあるか)、テーブルの上にLINQのと定期的SqlCommandsを混合することは危険であるということです。いつもSqlCommandsを使ってテーブルに挿入し、それを読むためのLinqコマンドはうまくいきます。どうやら、Linqは結果をキャッシュします。おそらく周りに道がありますが、それは明らかではありませんでした。

答えて

3

一時テーブルを使用して問題を解決することに問題はありません。 SqlCommandsとLINQを混在させる限り、危険要因については絶対に正しいです。これは、DataContextのを使用して、SQL文を実行するように簡単ですが、私もSqlCommandオブジェクトを心配しないでしょう。

private string _ConnectionString = "<your connection string>"; 

public void CreateTempTable() 
{ 
    using (MyDBDataContext dc = new MyDBDataContext(_ConnectionString)) 
    { 
     dc.ExecuteCommand("create table #temptab (recno int primary key not null)"); 
    } 
} 

public void DropTempTable() 
{ 
    using (MyDBDataContext dc = new MyDBDataContext(_ConnectionString)) 
    { 
     dc.ExecuteCommand("DROP TABLE #TEMPTAB"); 
    } 
} 

public void YourMethod() 
{ 
    CreateTempTable(); 

    using (MyDBDataContext dc = new MyDBDataContext(_ConnectionString)) 
    { 
     ... 
     ... do whatever you want (within reason) 
     ... 
    } 

    DropTempTable(); 
} 
0

「汎用ソリューション」として、あなたのコードが複数のスレッドで実行された場合にどのような/アプリ?私は大きなリストのソリューションは常に問題のドメインに関連していると思う。作業中の問題に対しては、通常の表を使用する方がよいでしょう。

"generic"リストテーブルをデータベースに作成しました。この表は、int、uniqueidentifierおよびvarcharという3つの列と、各リストを管理するための他の列で作成されています。私は考えていた: "それは多くの場合を処理するのに十分であるべきだ"。しかしすぐに、3つの整数のリストを使って結合を実行する必要があるタスクを受け取りました。その後、私は "generic"リストテーブルを再び作成しようとはしませんでした。

また、データベースコールごとにリストテーブルに複数の項目を挿入するSPを作成する方がよいでしょう。 2 db未満の往復で〜2000個のアイテムを簡単に挿入できます。あなたがやっていることによっては、パフォーマンスは問題ではないかもしれません。

EDIT:一時テーブルと一時テーブルが接続ごとにあることを忘れています。そのため、以前のマルチスレッドの引数は適切ではありませんでした。しかし、それは固定スキーマを強制するための一般的な解決策ではありません。

1

同様の状況がありますが、これはうまくいきますが、あなたが本当にクエリ可能なものを扱っていないということになりますので、この "with" LINQを簡単に使用することはできません。これはメソッドチェーンで動作するソリューションではありません。

私たちの最終的な解決策は、ストアドプロシージャで必要なものをスローし、それらの値が必要なときに一時テーブルに対してそのプロシージャの選択を書き込むことでした。これは妥協ですが、どちらも回避策です。少なくともストアドプロシージャを使用すると、デザイナーは呼び出しコードを生成し、ブラックボックス化された実装を使用するので、さらにチューニングする必要がある場合は、プロシージャ内で厳密に再コンパイルせずに行うことができます。

Linq2Sqlステートメントを書くことで、クエリの中で一時テーブルを使用できるようになり、複雑なシナリオのための厄介なSQL INステートメントを避けることができます。

0

Neilが提供するソリューションは実際に動作しますか?その一時テーブル、およびメソッドのそれぞれが独自のデータコンテキストを作成して処理している場合、接続が破棄された後も一時テーブルがそこに残っているとは思われません。

たとえそこにいたとしても、これはクエリーや接続がどのようにレンダリングされるのかを想定していると思いますが、linqの大きな問題については何も分かりません。エンジニアがより良い方法を思いついていくにつれて、彼が追いかけるような状況が起こるかもしれません。

私はストアドプロシージャでそれを行います。必要に応じて、結果セットを事前定義されたテーブルにいつでも戻すことができます。

+0

正直言って、私は一時テーブルを使って提供したソリューションをテストしていません。つまり、ソリューションは間違いなく "永久"テーブルを使用して動作します。また、DataContext.ExecuteCommand()メソッドを使用している理由は、LINQエンジンによってSQL文がまったく処理されないためです。送信するものが実行されるためです。 –

関連する問題