2009-06-17 69 views
7

在試圖解決:Linq臨時表 - 任何人都看到這個問題?

Linq .Contains with large set causes TDS error

我想我已經跨解決方案迷迷糊糊的,我想看看它是否接近問題的猶太方式。

(簡短摘要)我想linq連接與SQL中沒有(完全或至少容易)生成的記錄ID列表。這是一個很大的清單,經常會超過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()。

後記: 的一個問題,我有是在臺上混合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

作爲「通用解決方案」,如果你的代碼是在一個以上的線程運行什麼/應用?我認爲大清單解決方案總是與問題領域相關。對您正在處理的問題使用常規表格更好。

我曾經在數據庫中創建過「通用」列表。該表由三列創建:int,uniqueidentifier和varchar,以及用於管理每個列表的其他列。我在想:「它應該足以處理很多案件」。但很快我收到一個任務,要求使用三個整數列表執行一個連接。之後,我再也沒有嘗試過創建「通用」列表。

此外,最好創建一個SP,以便在每個數據庫調用中將多個項插入列表中。您可以在少於2分貝的往返中輕鬆插入〜2000個物品。原因,取決於你在做什麼,表現可能並不重要。

編輯:忘了它是一個臨時表和臨時表是每個連接,所以我以前的多線程參數是不正確的。但是,對於執行固定模式,這不是一個通用的解決方案。

1

我們有類似的情況,雖然這有效,但問題變成你並不真正處理Queryable,所以你不能輕易使用這個「與」LINQ。這不是一個適用於方法鏈的解決方案。

我們的最終解決方案就是在存儲過程中拋出我們想要的東西,並在需要這些值時將臨時表中的選擇寫入臨時表中。這是一種妥協,但都是解決方法。至少在存儲過程中,設計人員將爲您生成調用代碼,並且您有一個黑盒子實現,所以如果您需要進一步調整,您可以嚴格按照過程執行操作,而無需重新編譯。

在一個完美的世界中,將來會有一些編程Linq2Sql語句的支持,這些語句允許您在查詢中使用臨時表,避免在這種複雜場景中使用討厭的SQL IN語句。

0

Neil提供的解決方案是否真的有效?如果它是一個臨時表,並且每個方法都在創建和處理它自己的數據上下文,我不認爲臨時表會在連接斷開後仍然存在。

即使它在那裏,我認爲這將是一個區域,你將假設查詢和連接最終呈現的一些功能,這就是linq to sql的大問題 - 你只是不知道什麼隨着工程師想出更好的方法來做事,他可能會發生這種情況。

我會做一個存儲過程。如果您願意,您可以隨時將結果集返回到預定義的表格中。

+0

說實話,我還沒有測試過使用臨時表提供的解決方案。這就是說,解決方案肯定會使用「永久」表。另外,我使用DataContext.ExecuteCommand()方法的原因是因爲SQL語句根本不是由LINQ引擎處理的......你發送的是被運行的東西。 – 2011-02-04 20:00:48

相關問題