黒龍's Blog

明日から役立つ無駄知識をあなたに(仮)

ホーム 連絡をする 同期する ( RSS 2.0 ) Login
投稿数  170  : 記事  0  : コメント  2719  : トラックバック  26

ニュース

わんくま同盟に参加させていただきました。
どうぞよろしくお願いします。

自己紹介

コミュニティ

  • わんくま同盟
    わんくま同盟

書庫

前回(Linq to 色々その2)、前々回(Linq to 色々)に引き続きIQueryableの残りを作っていきます。

Where句を抽出してWeb Serviceのパラメータとするところまでは概ねうまくいっていたのですが気になる現象がみられました。

それはWhere指定した条件が最終的な列挙にも使用されているという現象です。(なので結果セットを作るところでkeywordとかを詰めなおしていた)

これはExpressionTreeからWhereを評価後に該当するWhere句を取っ払ってしまえばよく、そのためのExpressionTreeModifier<T>というクラスが存在していますので中身にWhere句部分を取っ払うようにしてみましょう。

Where句というのはWhereの抽出で行っていた中身にあるように実質はWhereメソッドの呼び出しになります。(Argument[0]が後続のSelect等のクエリ、Argument[1]がWhereの条件部分)なのでここをWhereの抽出時同様にVisitMethodCallをオーバライドするようにしましょう。こうすれば結果セットに対してのWhereはかからなくなるので期待通り結果のみつめればよくなります。

protected override Expression VisitMethodCall(MethodCallExpression node)
{
    if (node.Method.Name == "Where")
        return Visit(node.Arguments[0]);
    return base.VisitMethodCall(node);
}

で、いよいよ大物のグルメサーチAPIと行きたいところですがマスタ類も結局は必要になるので先にかたずけるとしましょう。前回ページング対応のものは作ったのですが同じ形でAPI毎に作るというのも面倒なのでほとんどのマスタ系呼び出しに共通するページングなしのQueryProviderを作成しましょう。

やりたいこととしては

  • URLを切り替えれるようにする
  • 結果のXMLから抽出するタグ名を指定できるように
  • 検索条件があれば指定できるように

あたりの事が出来ればひとまずよさそうです。というわけで。。。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Xml.Linq;
using System.Xml;
using System.Net;

namespace LinqToHotpepper
{
    /// <summary>
    /// ファクトリクラス
    /// </summary>
    public static class SimpleQueryProvider
    {
        /// <summary>
        /// ファクトリメソッド
        /// </summary>
        /// <param name="apiKey">発行されたAPIキー</param>
        /// <param name="baseUrl">リクエストURL</param>
        /// <param name="name">抽出対象のXML要素名</param>
        /// <param name="builder">結果のファクトリ</param>
        public static SimpleQueryProvider<T> Create<T>(string apiKey, string baseUrl, string name, Func<IEnumerable<XElement>, T> builder)
        {
            return new SimpleQueryProvider<T>(apiKey, baseUrl, name, builder, null);
        }
        /// <summary>
        /// ファクトリメソッド
        /// </summary>
        /// <param name="apiKey">発行されたAPIキー</param>
        /// <param name="baseUrl">リクエストURL</param>
        /// <param name="name">抽出対象のXML要素名</param>
        /// <param name="builder">結果のファクトリ</param>
        /// <param name="finder">要素から抽出を行うFinder</param>
        public static SimpleQueryProvider<T> Create<T>(string apiKey, string baseUrl, string name, Func<IEnumerable<XElement>, T> builder, EqualsFinder<T> finder)
        {
            return new SimpleQueryProvider<T>(apiKey, baseUrl, name, builder, finder);
        }
    }
    public class SimpleQueryProvider<T> : QueryProviderBase<T>
    {
        /// <summary>発行されたAPIキー</summary>
        private string key;
        /// <summary>リクエストURL</summary>
        private string baseUrl;
        /// <summary>要素から抽出を行うFinder</summary>
        private EqualsFinder<T> finder;
        /// <summary>抽出対象のXML要素名</summary>
        private string name;
        /// <summary>結果セットのファクトリ</summary>
        private Func<IEnumerable<XElement>, T> resultBuilder;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="apiKey">発行されたAPIキー</param>
        /// <param name="baseUrl">リクエストURL</param>
        /// <param name="name">抽出対象のXML要素名</param>
        /// <param name="builder">結果のファクトリ</param>
        /// <param name="finder">要素から抽出を行うFinder</param>
        public SimpleQueryProvider(string apiKey, string baseUrl, string name, Func<IEnumerable<XElement>, T> builder, EqualsFinder<T> finder)
        {
            this.key = apiKey;
            this.baseUrl = baseUrl;
            this.name = name;
            this.resultBuilder = builder;
            this.finder = finder;
        }
        /// <summary>
        /// パラメータチェック
        /// </summary>
        /// <param name="finder"></param>
        /// <returns></returns>
        private bool IsValidParameter(EqualsFinder<ShopResult> finder)
        {
            return true;
        }

        protected override IEnumerable<T> GetResult(Expression expression)
        {
            var sb = new StringBuilder(baseUrl);
            sb.AppendFormat("?key={0}", key);
            if (finder != null)
            {
                finder.Expression = expression;
                foreach (var item in finder.Results)
                {
                    sb.AppendFormat("&{0}={1}", item.Key, item.Value);                    
                }
            }

            var element = XDocument.Load(sb.ToString());

            //エラーチェック
            var error = element.Descendants("{http://webservice.recruit.co.jp/HotPepper/}error").FirstOrDefault();
            if (error != null) throw new InvalidQueryException(new Error(error).Message);

            var collection = element.Descendants("{http://webservice.recruit.co.jp/HotPepper/}" + name);

            yield return resultBuilder(collection);
        }
    }
}

SimpleQueryProvider<T>ですがQueryProviderBase<T> (abstractだったのでQueryProviderからQueryProviderBaseに名称変えました)をシンプルに実装しただけですね。同名のSimpleQueryProviderクラスはSimpleQueryProvider<T>に対するファクトリです。ジェネリッククラスのコンストラクタはいちいち<T>を書かないとダメなんですがジェネリックメソッドは引数からの型推論が効くのでジェネリックメソッドにはだいたい作っちゃうことが多いです。

こうすることでnew Query<ResultBase<CodeName>>(new SimpleQueryProvider<ResultBase<CodeName>>(...

なんて書き方がQuery.Create(SimpleQueryProvider.Create(...ですんじゃうので。で、呼び出し方はそのまんまですが

var foodQuery = Query.Create(SimpleQueryProvider.Create(
            <APIキー>,
            "http://webservice.recruit.co.jp/hotpepper/food/v1/",
            "food",
             x => new FoodResult()
             {
                 Results = x.Select(_ => new Food(_))
             },
             EqualsFinder.Creater((FoodResult _) => _.code
                , _ => _.keyword,
                _ => _.food_category)));
var query = from result in foodQuery
            from food in result.Results
            where result.keyword == "料理"
            select food;

foreach (var item in query)
{
    System.Diagnostics.Debug.WriteLine(item.Name);
}

みたいな感じにすることでOK。ページング対応の部分も必要なので前回のShopInfoQueryProviderをもとに今回のような汎用的な検索のページングバージョンを作成しましょう。

長くなったので続く。

投稿日時 : 2012年1月9日 1:32

コメント

# Linq to いろいろその4。ページング対応部分を整えてLinqToHotpepperを完成させる 2012/01/10 1:37 黒龍's Blog
Linq to いろいろその4。ページング対応部分を整えてLinqToHotpepperを完成させる

# over the counter blood thinners 2023/01/26 22:29 Jamessop
https://over-the-counter-drug.com/# over the counter testosterone

# stromectol 3 mg tablets price 2023/02/03 4:07 Jamescob
earch our drug database. Read here.
https://stromectolst.com/# ivermectin 1 cream
Everything information about medication. Prescription Drug Information, Interactions & Side.

# What side effects can this medication cause? Get here.
https://edonlinefast.com
Everything information about medication. Read here. 2023/02/16 21:51 EdPills
What side effects can this medication cause? Get here.
https://edonlinefast.com
Everything information about medication. Read here.

# buy erection pills 2023/02/17 7:34 PhilipEvact
Drug information. Comprehensive side effect and adverse reaction information.
https://edonlinefast.com buy ed pills online
Everything information about medication. Long-Term Effects.

# doxycycline 150 mg - https://doxycyclinesale.pro/# 2023/04/22 3:57 Doxycycline
doxycycline 150 mg - https://doxycyclinesale.pro/#

# prednisone 4 mg daily - https://prednisonesale.pro/# 2023/04/22 15:04 Prednisone
prednisone 4 mg daily - https://prednisonesale.pro/#

# wellcare over the counter ordering https://overthecounter.pro/# 2023/05/08 22:38 OtcJikoliuj
wellcare over the counter ordering https://overthecounter.pro/#

# over the counter appetite suppressant 2023/05/09 7:11 Gregorysew
https://overthecounter.pro/# over the counter testosterone

# cheap ed pills 2023/05/16 1:34 Mickeynix
http://edpills.pro/# top rated ed pills

# top rated ed pills: https://edpills.pro/# 2023/05/16 3:12 EdPillsPro
top rated ed pills: https://edpills.pro/#

# buy cytotec in usa 2023/06/05 10:16 Davidodota
http://prednisonepills.pro/# buy cheap prednisone

# where to get cytotec pills 2023/06/06 18:44 Davidodota
http://prednisonepills.pro/# prednisone no rx

# ed meds 2023/06/11 3:29 BennySpuse
http://edpillsfd.com/# ed medications

# sildenafil cost compare 100 mg 2023/06/27 6:33 DavidPaync
https://sildenafilpills.pro/# sildenafil 50 mg buy online price

# top ed pills 2023/06/28 22:36 Jamesweeva
http://edpill.pro/# mens ed pills

# sildenafil 100mg generic mexico 2023/06/29 2:48 DavidPaync
https://edpill.pro/# ed pills online

# sildenafil cream 2023/06/29 18:28 DavidPaync
http://sildenafilpills.pro/# sildenafil 50 mg tablet

# male ed pills 2023/06/30 13:02 JosephKarnE
http://edpill.pro/# top erection pills

# non prescription erection pills 2023/06/30 15:34 Jamesweeva
http://edpill.pro/# erection pills online

# Paxlovid buy online https://paxlovid.pro/# - paxlovid india 2023/07/03 3:51 Paxlovid
Paxlovid buy online https://paxlovid.pro/# - paxlovid india

# paxlovid generic https://paxlovid.store/
paxlovid cost without insurance 2023/07/13 21:38 Paxlovid
paxlovid generic https://paxlovid.store/
paxlovid cost without insurance

# Cost of Plavix without insurance https://plavix.guru/ buy clopidogrel bisulfate 2023/10/24 0:38 Plavixxx
Cost of Plavix without insurance https://plavix.guru/ buy clopidogrel bisulfate

# comprare farmaci online con ricetta https://farmaciait.pro/ farmacia online più conveniente 2023/12/04 10:09 Farmacia
comprare farmaci online con ricetta https://farmaciait.pro/ farmacia online più conveniente

# gates of olympus oyna - https://gatesofolympus.auction/ gates of olympus s&#305;rlar&#305; 2024/03/27 20:42 Olympic
gates of olympus oyna - https://gatesofolympus.auction/ gates of olympus s&#305;rlar&#305;

# purchase cytotec https://cytotec.club/ buy cytotec 2024/04/28 2:49 Cytotec
purchase cytotec https://cytotec.club/ buy cytotec

Post Feedback

タイトル
名前
Url:
コメント