我正在尝试更好地解决我的代码,代码重用等问题。
每次我想读一些行时,我都厌倦了输入以下内容:
using(SqlConnection conn = new SqlConnection(myConnString))
{
using(SqlCommand cmd = new SqlCommand(cmdTxt, conn))
{
conn.Open();
using(SqlDataReader rdr = cmd.ExecuteReader())
{
while(rdr.Read())
{
/* do something with rows */
}
}
}
}
我知道有LINQ to SQL(我不喜欢它)和实体框架(还是个孩子)。我没有问题必须输出我的查询,我只是不想每次都要输入命令contruction,row iterator等。
我环顾四周,发现了一些我觉得适合我的东西,并尝试实施它以使我更容易。正如您在注释中看到的,我收到SqlDataReader关闭的错误。我猜它可能是因为DataFactory.ExecuteReader()方法中的using语句。返回阅读器时,将在我的SqlConnection和SqlCommand变量上调用dispose方法。我在那儿吗?如果是这样,应该如何管理连接和命令变量?
编辑:我更新了我的代码示例,以更好地反映我正在做的事情。
public class DataFactory
{
public DataFactory()
{}
public DataFactory(string connectionString)
{
_connectionString = connectionString;
}
protected _connectionString = "Data Source=Localhost, etc, etc";
private string ConnectionString
{
get{return _connectionString;}
}
public SqlConnection GetSqlConnection()
{
return new SqlConnection(ConnectionString);
}
public SqlDataReader ExecuteReader(string cmdTxt)
{
using(SqlConnection conn = new SqlConnection(ConnectionString))
{
using(SqlCommand cmd = new SqlCommand(cmdTxt, conn))
{
conn.Open();
return cmd.ExecuteReader();
}
}
}
}
public IRepository<T>
{
T GetById(int id);
}
public MyTypeRepository: IRepository<MyType>
{
private static DataFactory _df = new DataFactory();
public MyType GetById(int id)
{
string cmdTxt = String.Format("SELECT Name FROM MyTable WHERE ID = {0}", id);
using(SqlDataReader rdr = _df.ExecuteReader(cmdTxt))
{
if(rdr.Read()) /* I get an error that the reader is already closed here */
{
return new MyType(
Convert.ToInt32(rdr["Id"]),
rdr["Name"]);
}
else
{
return null;
}
}
}
}
public class MyType
{
public MyType(int id, string name)
{
_id = id;
_name = name;
}
private string _name;
public string Name
{
get{return _name;}
}
private int _id;
public int Id
{
get{return _id;}
}
public override void ToString()
{
return string.Format("Name: {0}, Id: {1}", Name, Id);
}
}
public class Program
{
private static MyTypeRepository _mtRepo = new MyTypeRepository();
static void Main()
{
MyType myType = _mtRepo.GetById(1);
Console.WriteLine(myType.ToString());
}
}
我也想知道我正在做的事情是否有意义,或者,如果不是,如何实现类似的东西,以便我不必经常输入连接创建等。
答案 0 :(得分:2)
在使用数据读取器后关闭和/或处理数据读取器非常重要,然后每个想要使用DataFactory的人都应该记住这样做。我认为返回DataTable而不是SqlDataReader是个好主意,这样你的DataFactory不依赖于SqlDataReader。
我的意思是:
public DataTable ExecuteReader(string cmdTxt)
{
using(SqlConnection conn = new SqlConnection(ConnectionString))
{
using(SqlCommand cmd = new SqlCommand(cmdTxt, conn))
{
conn.Open();
using(SqlDataReader reader=cmd.ExecuteReader())
{
DataTable dt=new DataTable();
dt.Load(reader);
return dt;
}
}
}
}
修改强> 好点。我不喜欢数据表(我们使用NHibernate所以我实际上不在我们的应用程序中使用数据表) 因此,如果您想将数据读取器映射到您自己的对象,也许您可以使用数据映射器将数据读取器映射到您自己的对象,我的意思是:
public T[] ExecuteReader<T>(string cmdTxt)
{
using(SqlConnection conn = new SqlConnection(ConnectionString))
{
using(SqlCommand cmd = new SqlCommand(cmdTxt, conn))
{
conn.Open();
using(SqlDataReader reader=cmd.ExecuteReader())
{
var result=new List<T>();
while(reader.Read())
result.Add(ObjectMapper.MapReader<T>(reader));
return result.ToArray();
}
}
}
}
答案 1 :(得分:2)
您的方法ExecuteReader将在返回Reader之前关闭连接。相反,它应该实现如下:
public IDataReader ExecuteReader(string cmdTxt)
{
SqlConnection conn = new SqlConnection(...);
try
{
SqlCommand cmd = new SqlCommand(cmdTxt, conn);
conn.Open();
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
catch
{
conn.Close();
throw;
}
}
ExecuteReader方法的调用者需要处理IDataReader:
using(IDataReader reader = ExecuteReader(commandText))
{
...
} // reader will be disposed here and will close the connection.
请注意,上面的内容不会在SqlCommand对象上调用Dispose。根据我的经验以及使用Reflector查看SqlCommand,只要处理了SqlConnection,就没有必要。但是我相信如果您想要处理它,以下内容将会起作用:
public IDataReader ExecuteReader(string cmdTxt)
{
SqlConnection conn = new SqlConnection(...);
SqlCommand cmd = null;
try
{
cmd = new SqlCommand(cmdTxt, conn);
conn.Open();
IDataReader reader =
cmd.ExecuteReader(CommandBehavior.CloseConnection);
cmd.Dispose();
return reader;
}
catch
{
if (cmd != null) cmd.Dispose();
conn.Close();
throw;
}
}
答案 2 :(得分:1)
我所做的是使用查询创建XML文件,并使用XSLT转换生成我的DAL代码CS文件。您可以随意使用,在XML中声明参数并在XSLT等中生成具有适当签名的方法等。我有一个博客条目,涵盖了相关主题,如何integrate the XSLT transformation into your Visual Studio project。现在有人可能会争辩说使用类型化数据集是一回事并且是免费午餐,但在我的情况下,我使用基于BeginExecute / EndExecute的异步DAL。没有一个VS工具能够正确使用这种方法,所以我基本上必须构建自己的方法。
答案 3 :(得分:0)
我会说它并没有真正解耦 - 基本上你使用“使用System.Data.SqlClient”的任何模块都耦合到你的数据库。 DAL的重点是应用程序耦合到DAL,DAL耦合到数据库。