2009-06-17 13 views
7

Trong cố gắng để giải quyết:Các bảng tạm thời trong LINQ - Bất kỳ ai cũng thấy có vấn đề với điều này?

Linq .Contains with large set causes TDS error

Tôi nghĩ rằng tôi đã tình cờ một giải pháp, và tôi muốn để xem nếu nó là một cách kosher tiếp cận vấn đề.

(tóm tắt ngắn) Tôi muốn linq-join chống lại danh sách các id hồ sơ không phải là (hoàn toàn hoặc ít nhất là dễ dàng) được tạo trong SQL. Đó là một danh sách lớn và thường xuyên vượt quá giới hạn mục 2100 cho cuộc gọi TPC RPC. Vì vậy, những gì tôi đã làm trong SQL được ném chúng trong một bảng tạm thời, và sau đó tham gia chống lại điều đó khi tôi cần chúng.

Vì vậy, tôi đã làm như vậy trong Linq.

Trong file MyDB.dbml của tôi, tôi nói thêm:

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

Mở nhà thiết kế và đóng nó thêm các mục cần thiết ở đó, mặc dù cho đầy đủ, tôi sẽ trích dẫn từ tập tin 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)); 
        } 
      } 
    } 

Sau đó, nó đơn giản trở thành vấn đề xung quanh một số thứ trong mã. Nơi tôi thường có:

MyDBDataContext mydb = new MyDBDataContext(); 

Tôi phải chia sẻ kết nối của nó với SqlConnection bình thường để tôi có thể sử dụng kết nối để tạo bảng tạm thời. Sau đó nó có vẻ khá hữu dụng.

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(); 

Và sử dụng nó:

// 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; 

Có ai thấy một vấn đề với cách tiếp cận này là một giải pháp có mục đích chung cho việc sử dụng bảng tạm thời trong tham gia trong LINQ?

Nó giải quyết vấn đề của tôi một cách tuyệt vời, vì bây giờ tôi có thể làm một việc đơn giản tham gia vào LINQ thay vì phải sử dụng .Contains().

Postscript: Một vấn đề mà tôi có là trộn Linq và SqlCommands thông thường trên bàn (nơi đọc/ghi và thứ khác) có thể nguy hiểm. Luôn sử dụng SqlCommands để chèn vào bảng, và sau đó các lệnh LINQ để đọc nó hoạt động tốt. Rõ ràng, Linq lưu trữ kết quả - có thể có một cách xung quanh nó, nhưng nó không phải là hiển nhiên.

Trả lời

3

Tôi không thấy sự cố khi sử dụng bảng tạm thời để khắc phục sự cố của bạn. Theo như trộn SqlCommands và LINQ, bạn hoàn toàn chính xác về yếu tố nguy hiểm. Nó rất dễ dàng để thực hiện câu lệnh SQL của bạn sử dụng một DataContext, tôi sẽ không còn lo lắng về 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

Là một "giải pháp có mục đích chung", những gì nếu bạn đang chạy trong nhiều hơn một chủ đề/ứng dụng? Tôi nghĩ giải pháp danh sách lớn luôn liên quan đến miền vấn đề. Tốt hơn nên sử dụng một bảng thông thường cho vấn đề bạn đang làm việc.

Tôi đã từng tạo bảng danh sách "chung chung" trong cơ sở dữ liệu. Bảng được tạo ra với ba cột: int, uniqueidentifier và varchar, cùng với các cột khác để quản lý mỗi danh sách. Tôi đã suy nghĩ: "nó phải đủ để xử lý nhiều trường hợp". Nhưng chẳng mấy chốc tôi nhận được một nhiệm vụ đòi hỏi sự tham gia được thực hiện với một danh sách trên ba số nguyên.Sau đó, tôi không bao giờ cố tạo lại bảng danh sách "chung".

Ngoài ra, tốt hơn là tạo SP để chèn nhiều mục vào bảng danh sách trong mỗi cuộc gọi cơ sở dữ liệu. Bạn có thể dễ dàng chèn ~ 2000 mục trong ít hơn 2 chuyến đi vòng db. Nguyên nhân, tùy thuộc vào những gì bạn đang làm, hiệu suất có thể không quan trọng.

EDIT: quên nó là một bảng tạm thời và bảng tạm thời là cho mỗi kết nối, vì vậy đối số trước đó của tôi trên nhiều chủ đề là không thích hợp. Tuy nhiên, nó không phải là một giải pháp chung, để thực thi lược đồ cố định.

1

Chúng tôi có tình huống tương tự, và trong khi điều này làm việc, vấn đề trở thành bạn không thực sự đối phó với Queryables, vì vậy bạn không thể dễ dàng sử dụng "với" LINQ. Đây không phải là một giải pháp hoạt động với các chuỗi phương thức.

Giải pháp cuối cùng của chúng tôi là chỉ để ném những gì chúng tôi muốn trong một thủ tục lưu trữ, và viết lựa chọn trong thủ tục đó chống lại các bảng tạm thời khi chúng ta muốn những giá trị đó. Đó là một sự thỏa hiệp, nhưng cả hai đều là cách giải quyết. Ít nhất với proc được lưu trữ, nhà thiết kế sẽ tạo ra mã gọi cho bạn, và bạn có một hộp đen thực hiện vì vậy nếu bạn cần làm điều chỉnh thêm, bạn có thể làm như vậy đúng trong thủ tục, mà không biên dịch lại. Trong một thế giới hoàn hảo, sẽ có một số hỗ trợ trong tương lai để viết các câu lệnh Linq2Sql cho phép bạn sử dụng các bảng tạm thời trong các truy vấn của bạn, tránh câu lệnh sql IN khó chịu cho các kịch bản phức tạp như thế này.

0

Giải pháp do Neil cung cấp có thực sự hoạt động không? Nếu nó là một bảng tạm thời, và mỗi phương thức đang tạo và xử lý ngữ cảnh dữ liệu riêng của nó, tôi không nghĩ rằng bảng tạm thời sẽ vẫn ở đó sau khi kết nối bị ngắt. Thậm chí nếu nó ở đó, tôi nghĩ đây sẽ là một lĩnh vực mà bạn đang giả định một số chức năng về cách truy vấn và kết nối kết thúc, và đó là vấn đề lớn với LINQ to sql - bạn chỉ không biết cái gì có thể xảy ra suy giảm theo dõi khi các kỹ sư tìm ra cách làm tốt hơn.

Tôi sẽ làm điều đó trong một proc được lưu trữ. Bạn luôn có thể trả lại tập kết quả thành một bảng được xác định trước nếu bạn muốn.

+0

Thành thật mà nói, tôi chưa thử nghiệm giải pháp mà tôi đã cung cấp bằng các bảng tạm thời. Điều đó đang được nói, giải pháp chắc chắn sẽ làm việc bằng cách sử dụng bảng "vĩnh viễn". Ngoài ra, lý do tôi đang sử dụng phương thức DataContext.ExecuteCommand() là vì câu lệnh SQL không được xử lý bởi động cơ LINQ ... những gì bạn gửi là những gì được chạy. –

Các vấn đề liên quan