2009-03-27 40 views
8

Tôi đang viết lại SQL nội tuyến trong lớp lưu trữ của mình để sử dụng các thủ tục được lưu trữ thay thế (yêu cầu bảo mật). Sau khi sử dụng Fluent NHibernate và Linq2Sql trong quá khứ, tôi thấy nó cực kỳ khó sử dụng và không thích hợp.Cách thanh lịch nhất để sử dụng các thủ tục được lưu trữ là gì?

EDIT: Để làm rõ, tôi không tìm kiếm giải pháp ORM hoạt động với procs được lưu trữ. Tôi chỉ muốn một số lời khuyên về một cách tốt đẹp để viết mã dưới đây.

Có bất kỳ chiến lược nào để làm cho loại mã này càng thanh lịch càng tốt?

 string commandText = "dbo.Save"; 

     using (SqlConnection sql = new SqlConnection(_connString.ConnectionString)) 
     using (SqlCommand cmd = sql.CreateCommand()) 
     { 
      cmd.CommandText = commandText; 
      cmd.CommandType = CommandType.StoredProcedure; 

      SqlParameter idParam = new SqlParameter("identity", item.Identity); 
      idParam.Direction = ParameterDirection.Input; 

      SqlParameter nameParam = new SqlParameter("name", item.Name); 
      nameParam.Direction = ParameterDirection.Input; 

      SqlParameter descParam = new SqlParameter("desc", item.Description); 
      descParam.Direction = ParameterDirection.Input; 

      SqlParameter titleParam = new SqlParameter("title", item.) 
      descParam.Direction = ParameterDirection.Input; 

      //SNIP More parameters 

      cmd.Parameters.Add(idParam); 
      cmd.Parameters.Add(descParam); 
      cmd.Parameters.Add(titleParam); 
      //SNIP etc 

      sql.Open(); 

      cmd.ExecuteNonQuery(); 

      //Get out parameters 
     } 

     return item; 

Trả lời

10

Trong ứng dụng nội bộ của chúng tôi, chúng tôi thường sử dụng lớp SqlHelper có thể tìm thấy tại liên kết sau (tải về và mô tả): http://www.microsoft.com/downloads/details.aspx?familyid=f63d1f0a-9877-4a7b-88ec-0426b48df275&displaylang=en

Về cơ bản lớp SqlHelper mất đi một số nhu cầu khai báo đối tượng kết nối, lệnh vv và cho phép bạn gọi phương pháp để trở về đối tượng như DataSet

sau đó bạn có thể sử dụng SqlHelper như vậy:

public static int UpdateItem(int parameter1, int parameter2, string parameter3) 
    { 
     SqlParameter[] arParam = new SqlParameter[3]; 
     arParam[0] = new SqlParameter("@Parameter1", lotId); 
     arParam[1] = new SqlParameter("@Parameter2", saleId); 
     arParam[2] = new SqlParameter("@Parameter3", lotNumber); 


     return int.Parse(SqlHelper.ExecuteScalar(connString, CommandType.StoredProcedure, "spName", arParam).ToString(), CultureInfo.InvariantCulture); 
    } 

Hope this helps :)

+0

Ooh cảm ơn những người đứng đầu ở đó! Tôi không thấy điều này. –

+0

Có tin đồn rằng EntLib sẽ được cập nhật cho .NET 3.5 để hỗ trợ LINQ. –

+0

SqlHelper cũng sẽ lưu bộ nhớ cache các tham số trong _some_ của quá tải, mà sẽ lưu các chuyến đi đến db. Trong đoạn mã trên, .NET sẽ đi vòng quanh db để khám phá kiểu dữ liệu cho @ Parameter1, v.v. Hãy chắc chắn để đọc về việc sử dụng nó. – Daniel

2

Bạn có thể sử dụng SubSonic làm lớp ORM giữa lớp học và quy trình được lưu trữ. Đây là một số cơ bản example. Phil Haack cũng có một số article tốt.

Có một số thông tin tốt trong this other question.

EDIT: Vì bạn đã cập nhật câu hỏi của mình để cho biết bạn không muốn sử dụng ORM, SubSonic không dành cho bạn. Tuy nhiên, tôi sẽ để lại câu trả lời ở đây cho những người khác sử dụng procs được lưu trữ. :) Bạn cũng nên xem xét nếu có khả năng bạn có thể sử dụng nó.

+0

Cảm ơn tôi đã không nhìn thấy điều đó, tuy nhiên tôi khuyên không nên sử dụng công nghệ của bên thứ ba bên ngoài công cụ hiện có vì nó cần phải được khách hàng chấp thuận và phải mất độ tuổi. –

+0

Vì vậy, đừng nói với họ đó là "công nghệ của bên thứ ba". Bạn cũng nên cập nhật câu hỏi của mình với thông tin này. –

+0

Không thể thực sự thoát khỏi điều đó. Tôi sẽ xem xét nó để xem ý nghĩa của nó là gì, tôi sẽ lưu trữ nó trong ngân hàng để sử dụng sau này nếu không. –

2

Bạn có thể giảm một nửa giá trị bằng cách lấy InputSqlParameter của riêng bạn từ SqlParameter và thiết lập hướng đến đầu vào trong hàm tạo.

Điều đó sẽ cho phép bạn viết

cmd.Parameters.Add(new InputSqlParameter("title", item.title)); 
    cmd.Parameters.Add(new InputSqlParameter("property", item.property)); 

này cho thấy một mô hình, và cho phép bạn thiết lập một danh sách tên tham số và các lĩnh vực mục và làm tham số bổ sung trong một cho vòng lặp.

1

Giữ từng tham số cho một quy trình được lưu trữ trong một "lớp dữ liệu". Sử dụng chú thích để chỉ định những thông tin như tham số sproc "in" hoặc "out".

Sau đó, bạn có thể tải lớp từ mã máy khách, sau đó sử dụng sự phản chiếu để xây dựng tất cả các tham số cho sproc, thực thi sproc và tải các tham số đầu ra trở lại lớp dữ liệu.

Sạch hơn một chút: Có một lớp cho đầu vào và một lớp cho đầu ra (ngay cả khi một số vào/ra). Bằng cách đó nó là rõ ràng (để mã khách hàng) mà các thông số cần phải được lấp đầy trên đường và trong đó được trả lại. Điều này cũng làm giảm bớt sự cần thiết cho những chú thích đó.

+0

Thú vị ... Tôi sẽ chơi với số –

-1
using (var conn = new SqlConnection(ConnectionString)) 
using (var cmd = conn.CreateCommand()) 
{ 
    cmd.CommandText = "[dbo].[Save]"; 
    cmd.CommandType = CommandType.StoredProcedure; 

    cmd.Parameters.Add(new SqlParameter(
     "Identity", SqlDbType.Int) { Value = item.Identity }); 

    cmd.Parameters.Add(new SqlParameter(
     "Name", SqlDbType.NVarChar, 50) { Value = item.Name }); 

    cmd.Parameters.Add(new SqlParameter(
     "Title", SqlDbType.NVarChar, 100) { Value = item.Title }); 

    conn.Open(); 
    cmd.ExecuteNonQuery(); 
} 

Sau đây là cách nó có thể trông giống như với Ent Lib:

// Note, that you don't need to specify connection string here, 
// it will be automatically taken from a configuration file 
var db = DatabaseFactory.CreateDatabase(); 

using (var cmd = db.GetStoredProcCommand("[dbo].[Save]")) 
{ 
    db.AddInParameter(cmd, "Identity", DbType.Int32, item.Identity); 
    db.AddInParameter(cmd, "Name", DbType.String, item.Name); 
    db.AddInParameter(cmd, "Title", DbType.String, item.Title); 
    db.ExecuteNonQuery(cmd); 
} 

Bạn cũng có thể sử dụng phương pháp SqlHelper từ doanh nghiệp Thư viện để đơn giản hóa cú pháp này.

SqlHelper.ExecuteNonQuery(connectinString, 
    CommandType.StoredProcedure, "[dbo].[Save]", new SqlParameter[] 
     { 
      new SqlParameter("Identity", item.Identity), 
      new SqlParameter("Name", item.Name), 
      new SqlParameter("Title", item.Title) 
     }); 
+0

Không cần phải thử cuối cùng nếu sử dụng "sử dụng" nó gọi tự động xử lý mà chính nó gọi gần –

0

Thats funny Tôi đã hỏi một cách chính thức cùng một câu hỏi này. Vẫn đang tìm kiếm một giải pháp tốt.

Which ORM is the best when using Stored Procedures

+0

Họ đang thực sự đối diện câu hỏi. –

+0

@joe: nó không phải là cùng một câu hỏi. –

6

Grab một bản sao của Enterprise Library. Nó là một wrapper đẹp xung quanh ADO. Ví dụ:

using System.Data.Common; 
using System.Globalization; 
using Microsoft.Practices.EnterpriseLibrary.Data; 

Database db = DatabaseFactory.CreateDatabase(DatabaseType.MyDatabase.ToString()); 

using (DbCommand dbCommand = db.GetStoredProcCommand("dbo.MyStoredProc")) { 
    db.AddInParameter(dbCommand, "identity", DbType.Int32, item.Identity); 
    db.AddInParameter(dbCommand, "name", DbType.String, item.Name); 
    db.AddInParameter(dbCommand, "desc", DbType.String, item.Description); 
    db.AddInParameter(dbCommand, "title", DbType.String, item.Title); 

    db.ExecuteNonQuery(dbCommand); 
} // using dbCommand 
2

Tôi khuyên bạn nên sử dụng đối tượng SqlHelper của Ứng dụng Microsoft Blocks.

Đối với một tuyên bố như bạn đã liệt kê ở trên, tôi có thể làm như sau.

SqlHelper.ExecuteNonQuery(_connectionString, "MyProcName", 1, "NameValue", "Description", "Title"); 

Trình trợ giúp SQL cơ bản có một vài tham số.

  1. Các Connection String để kết nối với db
  2. Tên của thủ tục lưu trữ
  3. Một mảng các giá trị tham số, theo thứ tự mà chúng xuất hiện trong Stored Procedure.

Có một hạn chế hiệu suất rất nhỏ với phương pháp này rõ ràng là tạo ra mỗi thông số, nhưng tiết kiệm thời gian thường mất cân bằng vì nó quá nhỏ.

+0

Có thực sự là một nhược điểm hiệu suất? Trình biên dịch có quan tâm đến điều đó không? –

+0

Tôi thực sự đã thực hiện xong một loạt các thử nghiệm. với một thủ tục lưu trữ thông số 5 có sự khác biệt 7% khi phát hành từ 1 đến 1000 câu lệnh. Sau 1000 nó giảm xuống còn khoảng 4%. Khi tôi đạt khoảng 20000 lần chèn thì không có sự khác biệt. Nó xuất hiện liên kết với bộ nhớ đệm. –

+0

Nhưng thực sự đã đưa ra thời gian liên quan, hiệu suất differenct là hầu như không một cái gì đó bạn sẽ nhận thấy một sự khác biệt của 0,0003 giây cho các mục duy nhất. –

3

Tôi thường sử dụng một số biến thể của ví dụ sau đây, tùy thuộc vào môi trường của khóa học:

phương pháp helper cơ bản của tôi mà tôi gọi khắp mã của tôi

public static SqlCommand CreateStoredProcCmd(string name, SqlConnection con) 
{ 
    var cmd = new SqlCommand(name, con); 
    cmd.CommandType = CommandType.StoredProcedure; 
    return cmd; 
} 

public static void AddParams(this SqlCommand cmdObject, Params SqlParameter[] parameters) 
{ 
    foreach(SqlParameter param in parameters) 
    { 
    cmdObject.Parameters.add(param); 
    } 
} 

/* Any overloaded methods to create params receiving my param definitions 
in any manner that the usual new SqlParameter() constructor doesn't handle */ 
public static SqlParameter CreateSqlParam(string ParamName, 
              SqlDbType ParamType, 
              object value) 
{ 
    return CreateSqlParam(ParamName, ParamType, ParameterDirection.Input, value); 
} 

public static SqlParameter CreateSqlParam(string ParamName, 
              SqlDbType ParamType, 
              ParameterDirection ParamDir) 
{ 
    return CreateSqlParam(ParamName, ParamType, ParamDir, null; 
}       

public static SqlParameter CreateSqlParam(string ParamName, 
              SqlDbType ParamType, 
              ParameterDirection ParamDir, 
              object value) 
{ 
    var parm = new SqlParameter(ParamName, ParamType); 
    parm.Direction = ParamDir; 
    parm.Value = value; 
    return parm; 
} 

Bây giờ đây là làm thế nào tôi thiết lập up procs được lưu trữ của tôi và thêm tất cả các thông số của tôi một cách thanh lịch

public static string DoStuff() 
{ 
    using (var oCon = new SqlConnection("MyConnectionString")) 
    { 
     oCon.Open(); 
     var oCmd = CreateStoredProcCmd("sp_Name", oCon).AddParams(
      CreateSqlParam("Param1", SqlDBType.Int, 3), 
      CreateSqlParam("Param2", SqlDBType.VarChar, "Hello World"), 
      CreateSqlParam("Param3", SqlDBType.VarChar, ParameterDirection.Output) 
     ); 
     oCmd.Prepare(); 
     oCmd.ExecuteNonQuery(); 
     object outVal = oCmd.Parameters["Param3"]; 
     return null != outVal ? outVal.ToString() : String.Empty; 
    } 
} 
2

Để làm cho đoạn code một chút ít tiết thông số tôi đã luôn luôn bổ sung sử dụng

cmd.Parameters.AddWithValue("name", item.Name); 
cmd.Parameters.AddWithValue("title", item.Title); 
// and so on 
2

Input là hướng mặc định và bạn có thể rút ngắn các tham số bổ sung và có lẽ muốn khai báo SqlDBTypes cũng ...

cmd.Parameters.Add("identity", SqlDBType.???).Value = item.Identity; 
cmd.Parameters.Add("desc", SqlDbType.???, ?size?).Value = item.Description; 
cmd.Parameters.Add("title", SqlDBType.???, ?size?).Value = item.Title; 

//Output params generally don't need a value so... 
cmd.Parameters.Add("someOut", SqlDBType.???).Direction = ParameterDirection.Output; 
Các vấn đề liên quan