2010-03-02 91 views
5

Tôi đang cố gắng tìm hiểu xem có thể thực hiện lệnh nhập "chèn vào ... chọn" với LINQ to SQL hay không. Một chút mã LINQ to SQL sẽ cho phép tôi gửi một lệnh SQL duy nhất tới cơ sở dữ liệu có thể chèn nhiều hàng vào một bảng đã cho.Thực hiện lệnh INSERT INTO ... SELECT với LINQ to SQL

Ví dụ, làm thế nào để làm cho LINQ to SQL gửi câu lệnh T-SQL sau đến cơ sở dữ liệu SQL Server?

INSERT INTO Table1 
SELECT Table2.column1 + 1 AS column1, Table2.column2 + 2 AS column2 
WHERE Table2.column3 > 100 

tôi có thể đương nhiên đạt được điều này bằng cách sử dụng các chức năng DataContext.ExecuteCommand nhưng điều này sẽ được thực thi ngay lập tức mà không cần dùng lợi thế của giao dịch tự động xử lý bạn nhận được với DataContext.SubmitChanges. Tôi có một loạt các cập nhật bên cạnh điều này và tôi muốn tất cả chúng được khôi phục trong trường hợp có lỗi.

Bất kỳ ý tưởng nào?

UPDATE: Đây là mã thực tế:

 var bs_prep = 
      from b in dc.T_EDR_FILEBODies 
      join 
      unpaid in dc.V_UNPAIDs 
      on 
       b.NUM_ADC.Substring(1, 9) equals unpaid.NOCONT 
      join 
      acordo in dc.T_ACORDOS_RECOM_APREs 
      on 
       Convert.ToInt32(b.NUM_ADC.Substring(1, 9)) equals acordo.ID_Contrato 
      where 
       b.ID_EDR == id_edr 
       && 
       (
        unpaid.NUM_INCUMPRIMENTOS <= max_unpaid_consec 
        && 
        unpaid.TOTAL_NUM_INCUPRIMENTOS <= max_unpaid_nonconsec 
       ) 
       || 
       (
        acordo.Activo == true 
        && 
        acordo.Data_Recomeco <= now 
       ) 
      select new 
       { 
        ID_EDR = id_edr_filt, 
        NUM_LINHA = b.NUM_LINHA, 
        CODREJ = b.CODREJ, 
        HDT = b.HDT, 
        IMPORT = b.IMPORT, 
        NIB_DEV = b.NIB_DEV, 
        NUM_ADC = b.NUM_ADC, 
        REF_DD_BC = b.REF_DD_BC, 
        REF_MOV = b.REF_MOV 
       } 
      ; 


     dc.T_EDR_FILEBODies.InsertAllOnSubmit(
      bs_prep.Select(
       b => new T_EDR_FILEBODY{ 
        CODREJ = b.CODREJ, 
        HDT = b.HDT, 
        ID_EDR = b.ID_EDR, 
        IMPORT = b.IMPORT, 
        NIB_DEV = b.NIB_DEV, 
        NUM_ADC = b.NUM_ADC, 
        NUM_LINHA = b.NUM_LINHA, 
        REF_DD_BC = b.REF_DD_BC, 
        REF_MOV = b.REF_MOV 
       } 
      ) 
     ); 

Giải thích nhanh: Thực thể T_EDR_FILEBODies bản đồ vào một bảng cơ sở dữ liệu mà cơ bản lưu trữ các nội dung của một số tập tin văn bản chúng tôi nhập khẩu. Một bản ghi tương ứng với một dòng trong tệp văn bản.

Điều tôi đang cố gắng tạo phiên bản đã lọc của nội dung tệp bằng cách sao chép các bản ghi từ một tệp, cung cấp cho họ ID tệp mới (ID_EDR=id_edr_filt) nhưng lọc ra một số dòng. Các thực thể LINQ to SQL là ánh xạ trực tiếp tới các bảng cơ sở dữ liệu. Tôi đã không thêm mã vào datacontext của tôi cho đến nay. Họ có chìa khóa chính, hoặc nếu không tôi sẽ không thể chèn vào chúng (tôi đọc ở đâu đó tôi có thể loại bỏ ngoại lệ đó nếu tôi loại bỏ các khóa chính nhưng, như bạn thấy, điều đó sẽ không làm việc trong trường hợp của tôi).

Khi tôi chạy nó tôi nhận được ngoại lệ sau đây ném bởi InsertAllOnSubmit:

xây dựng Explicit của loại thực thể 'T_EDR_FILEBODY' trong truy vấn không được phép.

Tôi đoán tôi hiểu rằng việc xây dựng một thực thể rõ ràng bên trong truy vấn sẽ có vấn đề. Các thực thể được truy vấn trả về có thay đổi theo dõi, các thay đổi được dịch sang cơ sở dữ liệu khi các cuộc gọi con được gọi. Nhưng làm thế nào bạn có thể dịch, vào cơ sở dữ liệu, thay đổi về một thực thể được tạo ra ở phía khách hàng? Nhưng điều này thực sự có nghĩa là bạn không bao giờ có thể thực hiện lệnh INSERT INTO ... SELECT bằng cách sử dụng LINQ to SQL?

+1

Bạn có thể làm một "Sử dụng _tx như New TransactionScope()" và quấn ExecuteCommand và bất cứ điều gì khác trong nó? – StingyJack

+0

Vâng tôi đoán tôi có thể, và tôi có thể chỉ là cầu kỳ nhưng tôi cảm thấy khó chấp nhận rằng bạn chỉ không thể làm một chèn vào ... chọn tuyên bố bằng cách sử dụng LINQ. Nó sẽ là một chiếc vòng tay rất lớn. –

Trả lời

0

Bạn có thể sử dụng

ctx.Table1.InsertAllOnSubmit(
    mySelectEnumeration.Select(x => new Table1DT { ... }) 
); 
  • InsertAllOnSubmit chèn một số mục vào một LINQ to SQL bảng.
  • mySelectEnumeration là truy vấn chọn các mục sẽ được chèn.
  • Select(new Table1DT { ... }) là biến đổi cần thiết để chuyển đổi loại dữ liệu của bạn chọn truy vấn vào loại dữ liệu của bảng.

Hoặc bạn có thể sử dụng phương pháp ExecuteCommand và quản lý giao dịch theo cách thủ công.

using (var ctx = new DataClasses1DataContext()) { 
    ctx.Connection.Open(); 
    using (ctx.Transaction = ctx.Connection.BeginTransaction()) { 
     ctx.ExecuteCommand("sqlcommand"); 
     ctx.Transaction.Commit(); 
    } 
} 

Hoặc sử dụng phạm vi giao dịch:

using (var ctx = new DataClasses1DataContext()) { 
    using (var scope = new TransactionScope()) { 
     ctx.ExecuteCommand("sqlcommand"); 
     scope.Complete(); 
    } 
} 
+0

Tôi không chắc chắn tôi đã thực hiện đề xuất của bạn. Tôi không thể thấy làm thế nào để khởi tạo thể hiện Table1DT trên contructor nội tuyến dựa trên mySelectEnumeration. Làm thế nào để tôi tham khảo mySelectEnumeration? Hoặc tôi đã cố gắng gói gọn truy vấn thứ nhất (trả về một truy vấn) trong truy vấn khác với một hàm tạo nội tuyến Table1DT trên mệnh đề Chọn và do đó trả về một IQueryable . Nhưng tôi nhận được cùng một lỗi tôi nhận được đưa các nhà xây dựng nội tuyến trong truy vấn 1: Xây dựng rõ ràng của loại thực thể 'Table1DT' trong truy vấn không được phép. –

+1

Vì tôi không biết lớp DataContext cụ thể của bạn (ctx trong mẫu của tôi), tôi đã sử dụng trình giữ chỗ. 'Bảng 1' là trình giữ chỗ cho bảng vào các mục cần chèn vào. 'mySelectEnumeration' là kết quả của truy vấn bạn thực hiện để chọn các mục mà bạn muốn chèn. 'Table1DT' là kiểu dữ liệu của' Table1'. Và, '...' cho biết nơi bạn sẽ phải đặt thuộc tính của "Bảng 1", ví dụ: 'ID = x.identifier'. Tôi không thể cụ thể hơn nếu không biết DataContext của bạn. – AxelEckenberger

+0

Ok lỗi của tôi, tôi đoán tôi đã không đọc trả lời của bạn kỹ lưỡng như tôi nên (tôi bỏ lỡ "x =>"). Ok đã cố gắng đó, và tôi vẫn có ngoại lệ tương tự trên các cuộc gọi InsertAllOnSubmit: Xây dựng rõ ràng của loại thực thể 'Table1DT' trong truy vấn không được phép. (Tôi đang sử dụng cùng một ký hiệu bạn đã sử dụng). Tôi đã đọc về điều này và tôi đã có ý tưởng cho một số lý do bạn không thể xây dựng các thực thể bên trong các truy vấn. Tuy nhiên, không hiểu tại sao. –

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