繁体   English   中英

并行执行存储过程

[英]Execute stored procedures in parallel

我有这两种方法

public DataTable GetData1(int Id)
{
    DataTable dt = new DataTable();

    using (SqlConnection sqlcon = new SqlConnection(database.Connection.ConnectionString))
    {
        using (SqlCommand cmd = new SqlCommand("spGetData1", sqlcon))
        {
            cmd.CommandType = CommandType.StoredProcedure;

            cmd.Parameters.Add(new SqlParameter() { ParameterName = "@id", Value = Id});

            using (SqlDataAdapter da = new SqlDataAdapter(cmd))
            {
                da.Fill(dt);
            }
        }
    }

    return dt;
}

public DataTable GetData2(int Id)
{
    DataTable dt = new DataTable();

    using (SqlConnection sqlcon = new SqlConnection(database.Connection.ConnectionString))
    {
        using (SqlCommand cmd = new SqlCommand("spGetData2", sqlcon))
        {
            cmd.CommandType = CommandType.StoredProcedure;

            cmd.Parameters.Add(new SqlParameter() { ParameterName = "@id", Value = Id});

            using (SqlDataAdapter da = new SqlDataAdapter(cmd))
            {
                da.Fill(dt);
            }
        }
    }
    return dt;
}

我想立即执行它们,并获取数据以进行进一步处理。

我尝试了类似的东西

var task1 = Task.Factory.StartNew(() => database.Data.GetData1(1));
var task2 = Task.Factory.StartNew(() => database.Data.GetData2(2));

var taskList = new List<Task> { task1, task2 };

Task.WaitAll(taskList.ToArray());

但在最后一行它崩溃了

存在一个或多个错误。

内部的例外是

你调用的对象是空的。

堆栈跟踪

在System.Threading.Tasks.Task.WaitAll(Task []任务,Int32毫秒超时,CancellationToken cancelledToken)

connectionStringSystem.Data.Entity.DbContext.Database类获取

 public class DatabaseRepository : IDisposable
    {
        DbContext dbContext;

        public DatabaseRepository()
        {
             dbContext = new DbContext("connection string ...");
             Data = new DataRepository(dbContext.Database);

        }
        public DataRepository Data { get; set; }
}

在此处输入图片说明

但是即使我手动设置连接字符串,错误也是一样的,所以我不认为错误在这里。

   using (SqlConnection sqlcon = new SqlConnection("connection string ..."))
   {
      using (SqlCommand cmd = new SqlCommand("spGetData2", sqlcon))
      {
       ...
      }
   }

我怎样才能做到这一点? 我看到一些使用Async返回类型的示例,但是我不想重复这些方法。

database.Connection.ConnectionString静态字符串,否则由于 “非静态字段,方法或属性需要对象引用”, 因此无法编译

考虑到这一点,它不是因为它的静态而未被初始化的连接字符串,即使您有意将静态字符串初始化为Null,错误消息也将是:

InnerException = {“ ConnectionString属性尚未初始化。”}

这是一个再现, 除非您的GetData方法位于空对象中, 否则不会产生错误:

namespace database
{
public class Program
{
    static void Main(string[] args)
    {
        //WORKS!!
        var repro = new database.Data();
        var task1 = Task.Factory.StartNew(() => repro.GetData1(3));
        var task2 = Task.Factory.StartNew(() => repro.GetData2(5));
        var taskList = new List<Task> { task1, task2 };
        Task.WaitAll(taskList.ToArray());

        //FAILS WITH ERROR REPORTED!!
        repro = null;
        var task1 = Task.Factory.StartNew(() => repro.GetData1(3));
        var task2 = Task.Factory.StartNew(() => repro.GetData2(5));
        var taskList = new List<Task> { task1, task2 };
        Task.WaitAll(taskList.ToArray());
    }
}

class Data
{
    private string connectionString = "Server=.;Database=CRUD_Sample;Integrated Security=True;Asynchronous Processing = True;";
    public DataTable GetData1(int Id)
    {
        DataTable dt = new DataTable();
        using (SqlConnection sqlcon = new SqlConnection(connectionString))
        {
            using (SqlCommand cmd = new SqlCommand("Get_CustomerbyID", sqlcon))
            {
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.Add(new SqlParameter() { ParameterName = "@id", Value = Id });
                using (SqlDataAdapter da = new SqlDataAdapter(cmd))
                {
                    da.Fill(dt);
                }
            }
        }
        return dt;
    }

    public DataTable GetData2(int Id)
    {
        DataTable dt = new DataTable();
        using (SqlConnection sqlcon = new SqlConnection(connectionString))
        {
            using (SqlCommand cmd = new SqlCommand("Get_CustomerbyID", sqlcon))
            {
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.Add(new SqlParameter() { ParameterName = "@id", Value = Id });
                using (SqlDataAdapter da = new SqlDataAdapter(cmd))
                {
                    da.Fill(dt);
                }
            }
        }
        return dt;
    }
}
}

调试

您如何找到NullReferenceException的来源? 除了查看异常本身之外,关键是NRE会被准确地抛出在异常发生的位置,然后将鼠标悬停在“代码行”上的变量上,然后查看哪个对象为空。

更新:

Task.WaitAll导致当前线程阻塞,直到一切完成。 使用Task.WhenAll以免在等待任务完成时占用其他线程。

var task1 = Task.Factory.StartNew(() => database.Data.GetData1(1));
var task2 = Task.Factory.StartNew(() => database.Data.GetData2(2));

var taskList = new List<Task> { task1, task2 };

await Task.WhenAll(taskList.ToArray());

var result1 = await task1;
var result2 = await task2;

原始答案。 (仍然适用)

基于注释中提供的其他信息,我对封装该代码的类进行了假设。 并行执行时, database.Connection可能超出范围,这可能导致NRE。 在对象生命周期的早期提取连接字符串,并在获取数据时重新使用它。

 public class MyDataClass {

    string connectionString;
    private Database database;

    public MyDataClass(DbContext context) {
        this.database = context.Database;
        connectionString = database.Connection.ConnectionString;
    }

    public DataTable GetData1(int Id) {
        var dt = new DataTable();
        using (var sqlcon = new SqlConnection(connectionString)) {
            using (var cmd = new SqlCommand("spGetData1", sqlcon)) {
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.Add(new SqlParameter() { ParameterName = "@id", Value = Id });

                using (var da = new SqlDataAdapter(cmd)) {
                    da.Fill(dt);
                }
            }
        }

        return dt;
    }

    public DataTable GetData2(int Id) {
        var dt = new DataTable();
        using (var sqlcon = new SqlConnection(connectionString)) {
            using (var cmd = new SqlCommand("spGetData2", sqlcon)) {
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.Add(new SqlParameter() { ParameterName = "@id", Value = Id });

                using (var da = new SqlDataAdapter(cmd)) {
                    da.Fill(dt);
                }
            }
        }
        return dt;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM