我正在我的存储库类中重写内联SQL以改为使用存储过程(安全性要求)。在过去使用Fluent NHibernate和Linq2Sql之后,我发现它非常笨拙且不优雅。
编辑:为了澄清,我不是在寻找适用于存储过程的ORM解决方案。我只是想要一些很好的方法来编写下面的代码。
是否有任何策略可以使这类代码尽可能优雅?
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;
答案 0 :(得分:10)
在我们的内部应用程序中,我们通常使用SqlHelper类,可以在以下链接中找到(下载和描述):http://www.microsoft.com/downloads/details.aspx?familyid=f63d1f0a-9877-4a7b-88ec-0426b48df275&displaylang=en
本质上,SqlHelper类消除了声明连接对象,命令等的一些需要,并允许您调用返回对象的方法,如DataSet
然后您可以使用SqlHelper:
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);
}
希望这会有所帮助:)
答案 1 :(得分:6)
抓取Enterprise Library的副本。它是围绕ADO的一个很好的包装器。例如:
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 :(得分:3)
我通常使用以下示例的一些变体,具体取决于当然的环境:
我在整个代码中调用的基本辅助方法
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;
}
现在我在这里设置存储过程并优雅地添加所有参数
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;
}
}
答案 3 :(得分:2)
您可以使用SubSonic作为类和存储过程之间的ORM层。这是一个基本的example。 Phil Haack也有很好的article。
this other question中有一些很好的信息。
编辑:由于您已更新了问题以表明您不想使用ORM,因此SubSonic不适合您。但是,我会在这里为其他使用存储过程的人留下答案。 :)您还应该看看是否有可能使用它。
答案 4 :(得分:2)
您可以通过从SqlParameter派生自己的InputSqlParameter并在构造函数中将方向设置为Input来将行数减半。
那会让你写
cmd.Parameters.Add(new InputSqlParameter("title", item.title));
cmd.Parameters.Add(new InputSqlParameter("property", item.property));
这会显示一个模式,并允许您设置参数名称和项目字段列表,并在 for 循环中添加参数。
答案 5 :(得分:2)
我建议使用Microsoft Application Blocks SqlHelper对象。
对于您上面列出的声明,我可以执行以下操作。
SqlHelper.ExecuteNonQuery(_connectionString, "MyProcName", 1, "NameValue", "Description", "Title");
基本上SQL Helper需要一些参数。
这种方法在明确创建每个参数方面存在非常轻微的性能缺陷,但节省的时间通常会使它失去平衡,因为它太小了。
答案 6 :(得分:2)
为了使代码更简洁,我总是使用
添加参数cmd.Parameters.AddWithValue("name", item.Name);
cmd.Parameters.AddWithValue("title", item.Title);
// and so on
答案 7 :(得分:2)
输入是默认方向,你可以缩短参数添加,也可能想要声明SqlDBTypes ......
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;
答案 8 :(得分:1)
将给定存储过程的每个参数保存在“数据类”中。使用注释指定诸如“in”或“out”sproc参数之类的内容。
然后,您可以从客户端代码加载该类,然后使用反射为sproc构建所有参数,执行sproc,并将输出参数加载回数据类。
稍微清洁:有一个输入类和另一个输出类(即使有些输入/输出)。这样就很清楚(对于客户端代码)需要在路上填充哪些参数以及返回哪些参数。这也避免了对这些注释的需要。
答案 9 :(得分:0)
这很有趣我实际问了同样的问题。仍在寻找一个好的解决方案。
答案 10 :(得分:-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();
}
以下是 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);
}
您还可以使用Enterprise Library中的SqlHelper方法来简化此语法。
SqlHelper.ExecuteNonQuery(connectinString,
CommandType.StoredProcedure, "[dbo].[Save]", new SqlParameter[]
{
new SqlParameter("Identity", item.Identity),
new SqlParameter("Name", item.Name),
new SqlParameter("Title", item.Title)
});