C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

LINQのクエリを非同期にするには?

[トピック内 12 記事 (1 - 12 表示)]  << 0 >>

■83964 / inTopicNo.1)  LINQのクエリを非同期にするには?
  
□投稿者/ たなか (1回)-(2017/04/28(Fri) 11:18:42)

分類:[C#] 

VS2015 .net4.6 WPF EntityFramework 6.1.3

お世話になります。
以下のLINQを使用するメソッドを非同期にしたいのですが、
「join 句のいずれかの式の型が正しくありません」と表示されビルドできません。
よろしければ教えてください。
よろしくお願いします。
	
■同期
public List<MasterUserData.MasterUsrData> FilterNotPerformeType()
        {
            var result = from filter in MainDataCls.lstFilterdUserData
                         join master in MainDataCls.lstMasterUserData on filter.UserId equals master.UserId
                         select new MasterUserData.MasterUsrData
                         {
                             UserId = master.UserId,
                             eMail = master.eMail,
                             Name = master.Name
                         };
            return result.ToList();
        }

■非同期
        public async Task<MasterUserData.MasterUsrData> FilterNotPerformeTypeAsync()
        {
            var result = await from filter in MainDataCls.lstFilterdUserData
                         join  master in MainDataCls.lstMasterUserData on filter.UserId equals master.UserId
                         select new MasterUserData.MasterUsrData
                         {
                             UserId = master.UserId,
                             eMail = master.eMail,
                             Name = master.Name
                         }.ToListAsync;
            return result;
        }

引用返信 編集キー/
■83966 / inTopicNo.2)  Re[1]: LINQのクエリを非同期にするには?
□投稿者/ Hongliang (537回)-(2017/04/28(Fri) 11:38:56)
2017/04/28(Fri) 11:40:40 編集(投稿者)
コード、色々と間違っていませんか?
> public async Task<MasterUserData.MasterUsrData> FilterNotPerformeTypeAsync()
返値は
Task<MasterUserData.MasterUsrData>
じゃなくて
Task<List<MasterUserData.MasterUsrData>>
ですよね?

> select new MasterUserData.MasterUsrData
> {
>     UserId = master.UserId,
>     eMail = master.eMail,
>     Name = master.Name
> }.ToListAsync;
MasterUsrDataのコレクションではなく、単一のMasterUsrDataに対しるToListAsync呼び出し
(というか()がないのでデリゲートとして扱おうとして型がない)
になってます。

メソッドをasyncにするまでもなく、
同期版の最後のToList()をToListAsync()に置き換えるだけで十分かと思いますが。

public Task<List<MasterUserData.MasterUsrData>> FilterNotPerformeTypeAsync()
{
    var result = from ...
    return result.ToListAsync();
}

引用返信 編集キー/
■83968 / inTopicNo.3)  Re[2]: LINQのクエリを非同期にするには?
□投稿者/ たなか (2回)-(2017/04/28(Fri) 12:29:19)
No83966 (Hongliang さん) に返信

Hongliangさん返信ありがとうございます。
指摘いただいた箇所を修正しました。
public async Task<List<MasterUserData.MasterUsrData>> FilterNotPerformeTypeAsync()
ただ、同じErrが表示されます。

>メソッドをasyncにするまでもなく、
>同期版の最後のToList()をToListAsync()に置き換えるだけで十分かと思いますが。
こちらも同じく「join 句のいずれかの式の型が正しくありません」と表示されます。
引用返信 編集キー/
■83969 / inTopicNo.4)  Re[3]: LINQのクエリを非同期にするには?
□投稿者/ Hongliang (538回)-(2017/04/28(Fri) 13:04:12)
んん?

1. 同期版のみでビルドが通るか?
2. 同期版のを丸ごとコピーし、メソッド名だけ末尾にAsyncを付けるだけにして、ビルドが通るか?
3. 返値をTask<...>にし、ToListをToListAsyncに変えて、ビルドが通るか?

読む限り、そもそも 1. が偽であるような気がするのですが…。
引用返信 編集キー/
■83971 / inTopicNo.5)  Re[4]: LINQのクエリを非同期にするには?
□投稿者/ たなか (3回)-(2017/04/28(Fri) 13:45:00)
No83969 (Hongliang さん) に返信
おてすうおかけして申し訳ないです。

> 1. 同期版のみでビルドが通るか?
これはOKです。
同期版が動作をしているのを確認して非同期を作成しています。
なので、なぜ変更後joinでエラーになるのが分からず困っています。
非同期にするのと、LINQのクエリの構文は別だと考えているのですが・・・

> 2. 同期版のを丸ごとコピーし、メソッド名だけ末尾にAsyncを付けるだけにして、ビルドが通るか?
これもOKです。
メソッド名を変更しただけですよね?

> 3. 返値をTask<...>にし、ToListをToListAsyncに変えて、ビルドが通るか?
こうでしょうか?
この場合も、「join 句のいずれかの式の型が正しくありません」と表示されます。
(これって、一番最初に提示させていただいた非同期版と同じですよね?)
	
        public async Task<MasterUserData.MasterUsrData> FilterNotPerformeTypeAsync()
        {
             var result = await from filter in MainDataCls.lstFilterdUserData
                         join master in MainDataCls.lstMasterUserData on filter.UserId equals master.UserId
                         select new MasterUserData.MasterUsrData
                         {
                             UserId = master.UserId,
                             eMail = master.eMail,
                             Name = master.Name
                         }.ToListAsync;

            return result;
         }

引用返信 編集キー/
■83972 / inTopicNo.6)  Re[5]: LINQのクエリを非同期にするには?
□投稿者/ たなか (4回)-(2017/04/28(Fri) 13:53:20)
追加で以下に書き換えてみましたが、同じエラーとなります。
やはりjoinの部分がおかしいようです。

        public async Task<List<MasterUserData.MasterUsrData>> FilterNotPerformeTypeAsync()
        {
            List<MasterUserData.MasterUsrData> result = await from filter in MainDataCls.lstFilterdUserData
                         join master in MainDataCls.lstMasterUserData on filter.UserId equals master.UserId
                         select new MasterUserData.MasterUsrData
                         {
                             UserId = master.UserId,
                             eMail = master.eMail,
                             Name = master.Name
                         }.ToListAsync;

            return result;

引用返信 編集キー/
■83973 / inTopicNo.7)  Re[6]: LINQのクエリを非同期にするには?
□投稿者/ Hongliang (539回)-(2017/04/28(Fri) 14:17:57)
> public async Task<List<MasterUserData.MasterUsrData>> FilterNotPerformeTypeAsync()
> {
> List<MasterUserData.MasterUsrData> result = await from filter in MainDataCls.lstFilterdUserData
> join master in MainDataCls.lstMasterUserData on filter.UserId equals master.UserId
> select new MasterUserData.MasterUsrData
> {
> UserId = master.UserId,
> eMail = master.eMail,
> Name = master.Name
> }.ToListAsync;
>
> return result;

いやいや、同期版とToList(Async)の位置が全然違いますし、async/awaitを書けとも私は言っていませんよ?
引用返信 編集キー/
■83975 / inTopicNo.8)  Re[7]: LINQのクエリを非同期にするには?
□投稿者/ たなか (5回)-(2017/04/28(Fri) 14:32:17)
No83973 (Hongliang さん) に返信
> いやいや、同期版とToList(Async)の位置が全然違いますし、async/awaitを書けとも私は言っていませんよ?
申し訳ありません。
したのコードでよいのでしょうか?

エラー	CS1929	'IEnumerable<MasterUserData.MasterUsrData>' に 'ToListAsync' の定義が含まれておらず、
最も適している拡張メソッド オーバーロード 'QueryableExtensions.ToListAsync(IQueryable)' には 'IQueryable' 型のレシーバーが必要です。

エラー	CS0029	型 'System.Threading.Tasks.Task<System.Collections.Generic.List<SendMails.DataClass.MasterUserData.MasterUsrData>>' を
 'System.Collections.Generic.List<SendMails.DataClass.MasterUserData.MasterUsrData>' に暗黙的に変換できません


        public Task<List<MasterUserData.MasterUsrData>> FilterNotPerformeType()
        {
            var result = from filter in MainDataCls.lstFilterdUserData
                         join master in MainDataCls.lstMasterUserData on filter.UserId equals master.UserId
                         select new MasterUserData.MasterUsrData
                         {
                             UserId = master.UserId,
                             eMail = master.eMail,
                             Name = master.Name
                         };
            return result.ToListAsync();
        }



引用返信 編集キー/
■83976 / inTopicNo.9)  Re[8]: LINQのクエリを非同期にするには?
□投稿者/ Hongliang (540回)-(2017/04/28(Fri) 14:48:15)
あ、DBへのクエリではなく、すでにDBからメモリ上に読み込み済みのオブジェクトに対する処理ですか?
// Entity Frameworkは特に触ってないのでコードから読み取れない…。

LINQ to ObjectsにおいてはToListAsyncは定義されていないはずです。
なので、
return Task.Run(() => result.ToList());
などといった風に自分でTaskを起こす必要があるでしょう。
// それなりに件数が多くないと、ジョブ投入して完了待つって手間の方が処理コスト大きくなりそう。
引用返信 編集キー/
■83978 / inTopicNo.10)  Re[9]: LINQのクエリを非同期にするには?
□投稿者/ たなか (6回)-(2017/04/28(Fri) 15:20:44)
No83976 (Hongliang さん) に返信
> あ、DBへのクエリではなく、すでにDBからメモリ上に読み込み済みのオブジェクトに対する処理ですか?
はい。厳密にはCSVから読み込んだデータをメモリに入れ加工する箇所のコードが今回のものになります。

> LINQ to ObjectsにおいてはToListAsyncは定義されていないはずです。
そうなのですか?
https://msdn.microsoft.com/ja-jp/library/dn220257(v=vs.113).aspx
によると、特に記載が無いので使用できると思ったのですが・・・。
標準ではToList()のみですので、「ToListAsync」を使用するためにEntity Frameworkをインストールしたのですが?
何か勘違いしていますでしょうか?

> return Task.Run(() => result.ToList());
> などといった風に自分でTaskを起こす必要があるでしょう。
書いてみます・・・。

> // それなりに件数が多くないと、ジョブ投入して完了待つって手間の方が処理コスト大きくなりそう。
非同期の勉強と、想定している10万件のデータと2000件程度のデータのマージで、同期の方で10秒程度かかっているので
非同期を検討しています。


引用返信 編集キー/
■83979 / inTopicNo.11)  Re[10]: LINQのクエリを非同期にするには?
□投稿者/ Hongliang (541回)-(2017/04/28(Fri) 15:55:36)
>>LINQ to ObjectsにおいてはToListAsyncは定義されていないはずです。
> そうなのですか?
> https://msdn.microsoft.com/ja-jp/library/dn220257(v=vs.113).aspx
> によると、特に記載が無いので使用できると思ったのですが・・・。
> 標準ではToList()のみですので、「ToListAsync」を使用するためにEntity Frameworkをインストールしたのですが?
> 何か勘違いしていますでしょうか?

.NETのオブジェクトに対するLINQはLINQ to Objectsという名前で、主にIEnumerable<T>を対象にするものです。
System.Linq.Enumerableクラスに基本的な拡張メソッドが(ToListも含め)定義されていますが、これらはほぼ全てIEnumerable<T>を引数に取り、コレクションを返すときはIEnumerable<T>を返します。

Entity Frameworkにおいて、DBに対するLINQはLINQ to Entitiesという名前で、IQueryable<T>を対象にしています。
こちらはSystem.Linq.Queryableクラスに基本的な拡張メソッドが定義されています。もちろん引数や返値はIQueryable<T>が主です。

クエリ句
from ... in ... select ...
は、コンパイル時にSelectメソッド呼び出しに解決されますが、コレクションがIQueryable<T>であればQueryable.Select(...)が、そうでなければEnumerable.Select(...)が選択されます。

lstFilterdUserDataというのが配列やList<T>であるなら、当然IQueryable<T>は持っていないため、Enumerable.Selectが選択され、返値はIEnumerable<T>ということになります。
QueryableExtensions.ToListAsyncはIQueryable<T>を要求するので、当然呼び出しできません。
引用返信 編集キー/
■83980 / inTopicNo.12)  Re[11]: LINQのクエリを非同期にするには?
□投稿者/ たなか (7回)-(2017/04/28(Fri) 16:04:35)
No83979 (Hongliang さん) に返信
細かく説明していただきありがとうございます。
理解しました。





解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ