2009-01-30 13 views
8

Tôi đang sử dụng LINQ to SQL với một chương trình phụ trợ SQL Server (tất nhiên) làm ORM cho một dự án. Tôi cần lấy tập kết quả từ một thủ tục lưu sẵn trả về từ bảng được tạo động. Dưới đây là những gì các proc trông giống như:Làm thế nào để tôi nhận được LINQ to SQL để nhận ra tập kết quả của một thủ tục lưu trữ động?

CREATE procedure [RetailAdmin].[TitleSearch] (
@isbn varchar(50), @author varchar(50), 
@title varchar(50)) 
as 

declare @L_isbn varchar(50) 
declare @l_author varchar(50) 
declare @l_title varchar(50) 
declare @sql nvarchar(4000) 

set @L_isbn = rtrim(ltrim(@isbn)) 
set @l_author = rtrim(ltrim(@author)) 
set @l_title = rtrim(ltrim(@title)) 

CREATE TABLE #mytemp(
    [storeid] int not NULL, 
    [Author] [varchar](100) NULL, 
    [Title] [varchar](400) NULL, 
    [ISBN] [varchar](50) NULL, 
    [Imprint] [varchar](255) NULL, 
    [Edition] [varchar](255) NULL, 
    [Copyright] [varchar](100) NULL, 
    [stockonhand] [int] NULL 
) 

set @sql = 'select a.storeid, Author,Title, thirteendigitisbn ISBN, 
Imprint,Edition,Copyright ,b.stockonhand from ods.items a join ods.inventory b on  
a.itemkey = b.itemkey where b.stockonhand <> 0 ' 

if len(@l_author) > 0 
set @sql = @sql + ' and author like ''%'[email protected]_author+'%''' 

if len(@l_title) > 0 
set @sql = @sql + ' and title like ''%'[email protected]_title+'%''' 

if len(@L_isbn) > 0 
set @sql = @sql + ' and thirteendigitisbn like ''%'[email protected]_isbn+'%''' 

print @sql 

if len(@l_author) <> 0 or len(@l_title) <> 0 or len(@L_isbn) <> 0 

begin 
    insert into #mytemp 
    EXECUTE sp_executesql @sql 
end 


select * from #mytemp 
drop table #mytemp 

tôi đã không viết thủ tục này, nhưng có thể ảnh hưởng đến một sự thay đổi nếu có một vấn đề thực sự nghiêm trọng.

vấn đề hiện nay của tôi là khi tôi thêm thủ tục này để mô hình của tôi, các nhà thiết kế tạo ra chức năng này:

[Function(Name="RetailAdmin.TitleSearch")] 
public int TitleSearch([Parameter(DbType="VarChar(50)")] string isbn, 
    [Parameter(DbType="VarChar(50)")] string author, 
    [Parameter(DbType="VarChar(50)")] string title) 
{ 
    IExecuteResult result = this.ExecuteMethodCall(this, 
     ((MethodInfo)(MethodInfo.GetCurrentMethod())), isbn, author, title); 

    return ((int)(result.ReturnValue)); 
} 

mà không giống bất cứ điều gì giống như tập kết quả tôi nhận được khi tôi chạy proc bằng tay:

Result Set

Ai có thể cho tôi biết điều gì xảy ra ở đây?

Điều này về cơ bản là cùng một vấn đề như this question nhưng do cụm từ kém từ OP nó chưa bao giờ thực sự được trả lời.


Cảm ơn Marc đã trả lời của bạn. Tôi sẽ xem xét về việc thực hiện các thay đổi bạn đã đề xuất.

Vấn đề là bảng tạm thời. LINQ to Sql không biết phải làm gì với chúng. Điều này đặc biệt khó chẩn đoán, bởi vì Visual Studio lưu trữ thông tin về procs được lưu trữ, vì vậy khi ban đầu không tìm được kết quả, nó đặt trở lại làm kiểu số nguyên mặc định và không cập nhật khi tôi thực hiện thay đổi đối với proc được lưu trữ. Bắt VS để nhận ra một sự thay đổi đòi hỏi bạn phải:

  • Xóa proc từ dbml
  • xoá kết nối máy chủ từ Server Explorer
  • lưu dbml để buộc một biên dịch lại
  • đóng dự án và khởi động lại VS
  • tái kết nối máy chủ và nhập khẩu các proc

Bạn có thể không cần phải làm mỗi một trong những bước này, nhưng tha Tôi đã làm việc cho tôi. Những gì bạn cần làm, nếu bạn phải sử dụng một bảng tạm thời, là tạo ra một proc barebones đơn giản trả về lược đồ đúng, và sau đó thay đổi nó để làm những gì bạn muốn sau khi bạn nhập nó vào OR Designer.

Trả lời

5

Đầu tiên - QUAN TRỌNG - SQL của bạn dễ bị tiêm; lệnh bên trong phải được tham số:

if len(@l_author) > 0 
set @sql = @sql + ' and author like ''%''[email protected]+''%''' 

EXECUTE sp_executesql @sql, N'@author varchar(100)', @L_author 

này vượt qua giá trị của @L_author trong khi @author tham số trong lệnh động - ngăn chặn các cuộc tấn công tiêm.


Thứ hai - bạn không thực sự cần bảng tạm thời. Nó không làm bất cứ điều gì cho bạn ... bạn chỉ cần INSERT và SELECT. Có lẽ chỉ EXEC và để cho kết quả chảy vào người gọi một cách tự nhiên?

Trong các trường hợp khác, biến bảng sẽ phù hợp hơn, nhưng điều này không hoạt động với INSERT/EXEC.


Các cột có giống nhau cho mọi cuộc gọi không? Nếu vậy, hãy viết dbml theo cách thủ công, hoặc sử dụng một temp SP (chỉ với "WHERE 1 = 0" hoặc cái gì đó) để SET FMT_ONLY ON có thể hoạt động.

Nếu không (các cột khác nhau cho mỗi lần sử dụng), thì không có câu trả lời dễ dàng. Có lẽ sử dụng ADO.NET thông thường trong trường hợp này (ExecuteReader/IDataReader - và có lẽ ngay cả DataTable.Fill).

Tất nhiên, bạn có thể cho LINQ mất sự căng thẳng ... (C#):

... 
if(!string.IsNullOrEmpty(author)) { 
    query = query.Where(row => row.Author.Contains(author)); 
} 
... 

vv

+0

Hai điểm đầu tiên là quan trọng đối với câu hỏi đặc biệt này, nhưng nói chung tôi nghĩ [SET FMTONLY ON] [http://msdn.microsoft.com/en-us/library/ms173839.aspx] là một phần cốt lõi của vấn đề khi mã LINQ to SQL được tạo không trả lại kết quả mong đợi. Trong một số trường hợp, tôi đã đặt thành TẮT [http://www.fishofprey.com/2009/08/detecting-when-nettiers-is.html] khi tôi biết proc được lưu trữ sẽ không ảnh hưởng đến dữ liệu. I E. Chỉ chọn. –

5

Không có cách nào thực sự dễ dàng để thực hiện việc này. Tôi đã có cùng một vấn đề trong quá khứ. Tôi nghĩ rằng vấn đề là Linq để Sql không có cách nào để "tìm ra" mà loại sẽ được trả lại kể từ khi bạn đang xây dựng các câu lệnh SELECT tại thời gian thực hiện. Những gì tôi đã làm để có được xung quanh này, đã được trong proc lưu trữ, tôi đã làm chỉ là một lựa chọn và chọn tất cả các cột mà tôi có thể cần thiết. Sau đó, tôi đã có LINQ để Sql tạo ra các chức năng dựa trên đó. Sau đó, tôi quay trở lại SQL và thay đổi proc đã lưu trữ theo cách mà nó được cho là. Bí quyết ở đây không phải là để tạo lại DBML của bạn.

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