50064


Windowsフォームのイベントハンドラにて、EntityFramework6でDBクエリを実行しています。

ToListAsync()にawaitキーワードをつけて非同期実行とし、CancellationTokenを渡して処理のキャンセルを可能としています。  
しかしながら、下記コードで実行してみると、クエリの完了までUI操作がブロックされます。

意図した動作にならない原因は何なのでしょうか。

[code]

    private async void button1_Click(object sender, EventArgs e)
    {
        _cts = new CancellationTokenSource();
    
        using (var db = new SampleEntities())
        {
            // ここでawaitするがUIに制御が渡らない
            _result = await db.Database.SqlQuery<Result>("select fullname,productname from customers, products").ToListAsync(_cts.Token);
        }
    
        dataGridView1.DataSource = _result;
        statusLabel.Text = $"{_result.Count} records loaded.";   
    }
    
[/code]


CC BY-SA 4.0
2018-11-05T10:58:25.903
49983
2018-11-07T12:20:50.333
30852
question
c# winforms entity-framework
Windowsフォームのイベントハンドラ上でEntityFramework6のToListAsync()がawaitできない


多分ですが、一番時間がかかっているのが初期化

[code]

    var db = new SampleEntities()
    
[/code]

だと思います。  
アプリケーション起動後の最初のDbContextの初期化以外は意外とEntity Frameworkも遅い訳ではないですから。  
対策ですが、Usingの部分全体を非同期にすればUIが固まることは無いと思います。  
私はアプリケーション起動時に捨て接続も行ってます。


CC BY-SA 4.0
2018-11-06T07:10:33.253
50007
2018-11-06T07:10:33.253
18616
49983
answer


原因は、使用したDBドライバ(Oracle.ManagedDataAccess)が非同期クエリをサポートしていないためでした。  
接続先をSQL Serverに変更したら、コードはそのままで非同期実行できました。

なお、ドライバが非同期クエリをサポートしていない場合でも、  
下記のようにTask.Runで明示的に別スレッド実行すれば非同期実行は実現可能です。  
ただし、タスクをキャンセルした際に安全に処理が終了されていないかもしれません。

[code]

    private async void button1_Click(object sender, EventArgs e)
    {
        _cts = new CancellationTokenSource();
        var task = Task.Run<List<Result>>(async () =>
        {
            return await _db.Database.SqlQuery<Result>("select fullname,productname from customers, products").ToListAsync(_cts.Token);
        });
        _result = await task;
        dataGridView1.DataSource = _result;
        statusLabel.Text = $"{_result.Count} records loaded.";   
    }
    
[/code]


CC BY-SA 4.0
2018-11-07T12:20:50.333
50064
2018-11-07T12:20:50.333
30852
49983
answer