c# - 如何在数据访问层管理 SqlDataReader?

标签 c# data-access-layer

我正在尝试更好地处理代码解耦、代码重用等问题。

每次我想阅读一些行时,我都厌倦了输入以下内容:

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(我不喜欢它)和 Entity Framework(还是婴儿)。我不必输入查询就没有问题,我只是不想每次都输入命令构造、行迭代器等。

我环顾四周,发现了一些我认为对我有用的东西,并尝试实现它以使事情对我来说更容易。正如您在评论中看到的,我收到一条错误消息,指出 SqlDataReader 已关闭。我猜这可能是因为 DataFactory.ExecuteReader() 方法中的 using 语句。当读取器返回时,将对我的 SqlConnection 和 SqlCommand 变量调用 dispose 方法。我在那里吗?如果是这样,应该如何管理连接和命令变量?

编辑:我更新了我的代码示例以更好地反射(reflect)我在做什么。

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());
    }
}

我还想知道我正在做的事情是否有意义,或者,如果没有,如何实现类似的东西,这样我就不必经常输入连接创建等。

最佳答案

您的方法 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;
    }
}

关于c# - 如何在数据访问层管理 SqlDataReader?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/941126/

相关文章:

c# - 如何为多个分部 View 重用一个 Controller ?

c# - 如何将 JSON 对象数组反序列化为 C# 匿名类型?

c# - 试图了解如何抽象我的数据访问层

c# - 有没有办法在c#中注释掉字符串的一部分?

c# - unity loadConfiguration 失败

c# - 用c#异步处理Bitmap对象

.net - 单例 DAL 类

c# - 单元测试数据访问层的方法

c# - 为什么要避免动态 SQL 查询?有什么建议可以删除那里的坏部分并使用这些吗?

c# - LINQ2SQL 或 Entity Framework 或企业库?