いろいろといじってみました

Aug 17, 2011 at 4:42 PM

こんにちは

いろいろといじってみました。よろしければ、マージしてください。

検索系メソッドの問い合わせ条件について

検索系メソッドの問い合わせ条件について、現状は匿名型のみ許容する形になっていますが、必ずしもそうでなくても良いような気がして、いじってみました。

Db.fs

シンプルにしてみました

  let toExprCtxt(condition:obj) =
    let typ = condition.GetType()
    let meta = Meta.makeAnonymousMeta typ
    meta.ExtractProperties condition

Meta.fs

たまに動的にSQLを作成してパラメータが可変することもあるかと思い、IDictionaryにも対応できるようにしてみました。

  let newAnonymousMeta (typ:Type) =
    let extractor (obj:obj) =
      if typeof<IDictionary>.IsAssignableFrom(typ) then
        let m = obj :?> IDictionary
        seq {
          for key in m.Keys ->
            key.ToString(),
            (
              m.[key],
              if m.[key] = null then
                typeof<string>
              else
                m.[key].GetType()
            )
        }
        |> dict
      else
        typ.GetProperties() 
        |> Array.map (fun prop -> prop, prop.Name, prop.PropertyType)
        |> Seq.map (fun (prop, propName, propType) -> 
           propName, (prop.GetValue(obj, null), propType) )
        |> dict
    { ExtractProperties = extractor }

DataGridView等のDataSourceへのバインド

現状は<dynamic>でデータを取得して、DataGridViewのDataSourceに設定してもうまく表示できません。

かといって、都度SQLに対応したPOCOを作成するのも面倒です。

DataTable等で返してきてくれるメソッドを作ればよいのですが、なんだか現状のメソッドのポリシーに反しそうなので、DataRowViewのリストで返してもらえるように修正してみました。

Db.fs

open System.Xml
open System.ComponentModel
  member this.GetReaderHandler typ =
    if typ = typeof || typeof.IsAssignableFrom typ then
      (fun reader -> this.MakeDynamicObjectList reader)
    elif typ = typeof then
      (fun reader -> this.MakeDataRowViewList reader)
    elif Meta.isEntityType typ then 
      (fun reader -> this.MakeEntityList (Meta.makeEntityMeta typ dialect) reader)
    elif FSharpType.IsTuple(typ) then 
      (fun reader -> this.MakeTupleList (Meta.makeTupleMeta typ dialect) reader)
    else 
      (fun reader -> this.MakeSingleList typ reader)
  member this.MakeDataRowViewList reader =
    let dt = new DataTable()
    dt.Load(reader)
    let ls = dt :> IListSource
    seq{
      for item in ls.GetList() do
        yield item }

その他気づいた点

  • PaginateAndCountメソッドは引数のoffset、limitがint型ですが、戻り値のcountがlong型なのは微妙に感じました。(重箱の隅をつつくような指摘でごめんなさい)
  • 上記でDataRowViewの実装をして思ったのですが、CaseInsensitiveDynamicObjectはICustomTypeDescriptorを実装すれば、DataGridView等のDataSourceに設定しても問題ないのかもしれません。

 

以上

Aug 18, 2011 at 10:02 AM

フィードバックありがとうございます!

 

検索系メソッドの問い合わせ条件について

匿名型のプロパティにIDictionary<String, Object>を持てるのですが、それでも匿名型の代わりにIDictionaryを指定できたほうがうれしいでしょうか?

現在匿名型だけを受け付けるようにしている理由は、そのほうが使いやすい(シンプルで覚えやすい、インタフェースが統一されてきれい)だろうと考えたからです。

パラメータが可変の場合でも、SQLではどのみちパラメータを押さえないといけないので、可変であることが理由でIDictionaryのほうが便利になることもないと思います。

ただし、匿名型の代わりにIDictionaryを指定できたほうが利便性が高い局面がある、ということであれば許容してもいいかなと思います。

意見を聞かせてください。

 

DataGridView等のDataSourceへのバインド

DataSourceへバインドできるかどうかという観点は持っていませんでした。確かにできたほうが便利ですね。

CaseInsensitiveDynamicObjectでICustomTypeDescriptorを実装する方法で検討したいと思います。

DataTableを返すのはちょっとインタフェースが統一できないので、ご指摘の通り、ポリシーから外れてしまいますね。

 

PaginateAndCountメソッドは引数のoffset、limitがint型ですが、戻り値のcountがlong型なのは微妙

たしかに。。。統一する方向で考えます。やるなら全部long型ですよね。

Aug 18, 2011 at 4:19 PM

こんばんは

 

検索系メソッドの問い合わせ条件について

匿名型のプロパティにIDictionary<String, Object>を持てるのですが、それでも匿名型の代わりにIDictionaryを指定できたほうがうれしいでしょうか?

確かに、そうですね。私頭が固いですね。(;^_^A

現在匿名型だけを受け付けるようにしている理由は、そのほうが使いやすい(シンプルで覚えやすい、インタフェースが統一されてきれい)だろうと考えたからです。

ただ、匿名型のみ許容でなくても良いような気がします。マニュアルはあくまで匿名型だけの記述でよいと思うのですが、実は何でもいれられるみたいな。

既存のクラス(生成したエンティティ等)に値を設定して、それを検索条件に指定することもあるのかな、なんて思っています。

 

DataGridView等のDataSourceへのバインド

DataSourceへバインドできるかどうかという観点は持っていませんでした。確かにできたほうが便利ですね。

CaseInsensitiveDynamicObjectでICustomTypeDescriptorを実装する方法で検討したいと思います。

そうですよね。そっちのほうが奇麗ですね。よろしくおねがいします。

 

要望

ずうずうしくも、要望しちゃいます。

IDataReaderを返すメソッド

たまに個々のRDBMS特有の型のデータを取得したい場合があります。CLOB/BLOBもstringやbyte[]として一度に取得したら、メモリを浪費する場合もあります。

DbConnectionを直接使え、っていう話もありますが、やはりSomaのSQL記述を活用したいです。

IDataReader ExecuteReader(string sql, object  condition)的なメソッドがあると嬉しいですね。

(protectedでも良い、とも思ったのですがF#ってprotectedなメソッド作れないっぽいですね。)

 

では。

Aug 19, 2011 at 7:43 AM
 ただ、匿名型のみ許容でなくても良いような気がします。マニュアルはあくまで匿名型だけの記述でよいと思うのですが、実は何でもいれられるみたいな。

既存のクラス(生成したエンティティ等)に値を設定して、それを検索条件に指定することもあるのかな、なんて思っています。

そうですねぇ。どうせシグネチャとしてはObject型を受け入れるようになっているわけですし、IDictionaryとPOCOにも対応したいと思います。

 

ずうずうしくも、要望しちゃいます。

IDataReaderを返すメソッド

たまに個々のRDBMS特有の型のデータを取得したい場合があります。CLOB/BLOBもstringやbyte[]として一度に取得したら、メモリを浪費する場合もあります。

DbConnectionを直接使え、っていう話もありますが、やはりSomaのSQL記述を活用したいです。

IDataReader ExecuteReader(string sql, object  condition)的なメソッドがあると嬉しいですね。

(protectedでも良い、とも思ったのですがF#ってprotectedなメソッド作れないっぽいですね。)

要望大歓迎です。

IDataReaderを直接触りたいというのはわかります、そういうケースありますね。ただ、ポリシーとしてIDataReaderのクローズはフレームワーク側でやりたいな、とおもいます。こんな感じにしようと思います。

public T HandleReader<T>(string sql, object condition, Func<IDataReader, T> handler)

 

 

Aug 19, 2011 at 3:52 PM

こんばんは、お世話になってます。

 

DataReaderを直接触りたいというのはわかります、そういうケースありますね。ただ、ポリシーとしてIDataReaderのクローズはフレームワーク側でやりたいな、とおもいます。こんな感じにしようと思います。

public T HandleReader<T>(string sql, object condition, Func<IDataReader, T> handler)

 

ベストだと思います。開発していると、やはり初心者やセンスがない人は、どうしてもクローズ(DBに限らず)ということを忘れがちです。

Soma側でIDisposableなインスタンスをすべて管理するというポリシーは崩さないほうがよさそうですね。

 

では。

Aug 21, 2011 at 4:08 AM

このスレッドで要望いただいた点、指摘していただいた点はすべてSoma-1.5.0.0に反映させました。

http://soma.codeplex.com/releases/view/72054

 

ちなみにですが、DataReaderを直接さわるC#用のシグネチャは、最終的に次のようになりました。

public T ExecuteReader<T>(Func<DbDataReader, T> handler, string  sql, object condition);