运行数据库访问任务的最佳方式,返回对象,在单独的线程保持UI响应?

时间:2012-12-01 20:25:14

标签: c# .net multithreading data-access-layer splash-screen

[Windows表格应用程序& .NET 4.0]

我需要执行返回对象(类列表或简单类)的数据库访问方法。

此外,我还需要在主线程初始化时打开响应的表单。

我需要在单独的线程上运行它们,以保持用户界面的响应性,当然还能够将结果传递回主线程以进行UI更新。

我一直在阅读有关各种方法的书籍。

我明白我的工作可以通过以下方式完成:

  • BackgroundWorker的
  • 线程类
  • 任务类

我应该深入研究哪一个?

更新:使用建议的Task类我使用这个来获得交叉线程安全的错误:

private void BtnCheckClick(object sender, EventArgs e)
{
    var itm =   Task<JDEItemLotAvailability>.Factory.StartNew(() =>
                             Dal.GetLotAvailabilityF41021(
                                                         txtLot.Text,
                                                         cmbMcu.SelectedItem.ToString(),
                                                         cmbLocn.SelectedItem.ToString())
                            );
       lblDescriptionValue.Text = itm.Result.Description;
       lblItemCodeValue.Text = itm.Result.Code;
       lblQuantityValue.Text = itm.Result.AvailableQuantity.ToString();
       LotFocus(true);
}

在上面的例子中,我在cmbMcu控件中得到异常而不是txtLot。

2 个答案:

答案 0 :(得分:1)

我已经使用Thread完成了很多项目,但是Task应该更容易使用。

这是演示如何使用Threads进行异步操作。

这是将数据返回给ui的类:

public class MyAsyncClass
{

    public delegate void NotifyComplete(DataSet data);
    public event NotifyComplete NotifyCompleteEvent;

    //Starts async thread...
    public void Start()
    {
        System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(DoSomeJob));
        t.Start();
    }

    void DoSomeJob()
    {
        //just wait 5 sec for nothing special...
        System.Threading.Thread.Sleep(5000);
        if (NotifyCompleteEvent != null)
        {
            //TODO: fill your data...
            DataSet ds = new System.Data.DataSet();

            NotifyCompleteEvent(ds);
        }
    }
}

这是ui实施:

    MyAsyncClass myClass = null;


    private void button2_Click(object sender, EventArgs e)
    {
        myClass = new MyAsyncClass();
        myClass.NotifyCompleteEvent += new MyAsyncClass.NotifyComplete(myClass_NotifyCompleteEvent);
        //here I start the job inside working class...
        myClass.Start();
    }

    //here my class is notified from working class when job is completed...
    delegate void myClassDelegate(DataSet data);
    void myClass_NotifyCompleteEvent(DataSet data)
    {
        if (this.InvokeRequired)
        {
            Delegate d = new myClassDelegate(myClass_NotifyCompleteEvent);
            this.Invoke(d, new object[] { data });
        }
        else
        {
            //TODO: show your data
            MessageBox.Show("Data retrieved!");
        }
    }

答案 1 :(得分:1)

我会使用 Task 类,它很容易同步它,它已经为返回对象提供了支持。

var task = Task.Factory.StartNew(
    () => GetDatabaseData(someArguments),
    TaskCreationOptions.LongRunning);

// Example method
public DataSet GetDatabaseData(object args) { ... }

这会告诉 scheduler 创建并开始一个新任务并给它一个暗示,如果调度程序不使用线程池线程可能是个好主意使用线程池。无论如何,您现在可以决定如何同步。

例如,要实现与Gregor Primar的答案类似的行为,您可以使用 ContinueWith 方法设置延续,如下所示,

task.ContinueWith(oldTask => ProcessReturnedData(oldTask.Result));

// Example method
public IEnumerable<SomeEntity> ProcessReturnedData(DataSet data) { ... }

将在ProcessReturnedData对象执行完毕后调度task方法。请注意,即使task由于某种原因失败,也会调用此方法,因此它可能不总是一个好的解决方案 - 或者您必须在提供的委托中进行一些检查。

如果你想在主线程上进行非阻塞等待并在那里使用返回的对象,你只需使用 Wait 方法。

task.Wait(); // Makes current thread wait until the task is comnpleted.
DataSet result = task.Result; // Accessing the result object.