11

私が理解している限り、LINQ がサポートしていて、現在 Scala がそのコレクション ライブラリでサポートしていない唯一のものは、SQL データベースとの統合です。

私が理解している限り、LINQはさまざまな操作を「蓄積」でき、そこで処理するようにクエリされたときにデータベースに「全体」ステートメントを与えることができるため、単純なSELECT最初のテーブル全体がVMのデータ構造にコピーされるのを防ぎます。

もし間違っていたら、訂正していただけると幸いです。

そうでない場合、Scala で同じものをサポートするには何が必要ですか?

コレクション インターフェイスを実装するライブラリを作成することは可能ではないでしょうか。ただし、それをサポートするデータ構造はありませんが、次のコレクションで必要なデータベース ステートメントにアセンブルされる文字列はありませんか?

それとも、私の観察は完全に間違っていますか?

4

5 に答える 5

13

Scalaは式ツリーを実験的にサポートしています。型のパラメーターを期待するメソッドに無名関数を引数として渡すとscala.reflect.Code[A]、ASTが得られます。

scala> import scala.reflect.Code      
import scala.reflect.Code 
scala> def codeOf[A](code: Code[A]) = code
codeOf: [A](code:scala.reflect.Code[A])scala.reflect.Code[A]
scala> codeOf((x: Int) => x * x).tree 
res8: scala.reflect.Tree=Function(List(LocalValue(NoSymbol,x,PrefixedType(ThisType(Class(scala)),Class(scala.Int)))),Apply(Select(Ident(LocalValue(NoSymbol,x,PrefixedType(ThisType(Class(scala)),Class(scala.Int)))),Method(scala.Int.$times,MethodType(List(LocalValue(NoSymbol,x$1,PrefixedType(ThisType(Class(scala)),Class(scala.Int)))),PrefixedType(ThisType(Class(scala)),Class(scala.Int))))),List(Ident(LocalValue(NoSymbol,x,PrefixedType(ThisType(Class(scala)),Class(scala.Int)))))))

これは、ScalaDays2010で著者のJohannesRudolphによって提示されたバイトコード生成ライブラリ「ニーモニック」で使用されています。

于 2010-12-06T21:57:08.490 に答える
13

ScalaQuery の作成者として、Stilgar の説明に追加することはあまりありません。Scala に欠けている LINQ の部分は、実際には式ツリーです。これが、ScalaQuery がエンティティの基本型ではなく、列型とテーブル型ですべての計算を実行する理由です。

テーブルをその列のプロジェクション (タプル) を持つ Table オブジェクトとして宣言します。次に例を示します。

class User extends Table[(Int, String)] {
  def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
  def name = column[String]("name")
  def * = id ~ name
}

User.id と User.name は、それぞれ Column[Int] と Column[String] 型になりました。すべての計算は Query モナドで実行されます (これは、データベース クエリから作成する必要のある SQL ステートメントよりも自然なデータベース クエリの表現です)。次のクエリを実行します。

val q = for(u <- User if u.id < 5) yield u.name

いくつかの暗黙的な変換と脱糖の後、これは次のように変換されます。

val q:Query[String] =
  Query[User.type](User).filter(u => u.id < ConstColumn[Int](5)).map(u => u.name)

filter メソッドと map メソッドは、クエリを作成するために引数を式ツリーとして検査する必要はなく、実行するだけです。型からわかるように、表面的には「u.id:Int < 5:Int」に見えますが、実は「u.id:Column[Int] < u.id:Column[Int]」です。この式を実行すると、Operator.Relational("<", NamedColumn("user", "id"), ConstColumn(5)) のようなクエリ AST が生成されます。同様に、Query モナドの「filter」および「map」メソッドは、実際にはフィルタリングとマッピングを実行しませんが、代わりにこれらの操作を記述する AST を構築します。

次に、QueryBuilder はこの AST を使用して、データベースの実際の SQL ステートメントを (DBMS 固有の構文で) 構築します。

ScalaQLでは、コンパイラ プラグインを使用して式ツリーを直接操作し、データベース クエリで許可されている言語サブセットのみが含まれていることを確認し、クエリを静的に構築する代替アプローチが採用されています。

于 2010-12-06T21:41:35.153 に答える
5

LINQ を使用すると、コンパイラは、ラムダ式が IEnumerable または IQueryable にコンパイルされているかどうかを確認します。最初のものは Scala コレクションのように機能します。2 つ目は、式を式ツリー (つまり、データ構造) にコンパイルします。LINQ の強みは、コンパイラ自体がラムダを式ツリーに変換できることです。コレクション用に持っているものと同様のインターフェイスを使用して式ツリーを構築するライブラリを作成できますが、コンパイラに (JVM コードではなく) ラムダからデータ構造を構築させるにはどうすればよいでしょうか?

そうは言っても、この点でScalaが何を提供しているかはわかりません。Scala でラムダからデータ構造を構築することは可能かもしれませんが、いずれにせよ、データベースのサポートを構築するにはコンパイラに同様の機能が必要だと思います。プロバイダーを構築できる基になるデータ ソースはデータベースだけではないことに注意してください。たとえば、Active Directory や Ebay API などの LINQ プロバイダーは多数あります。

編集: APIだけが存在できないのはなぜですか?

クエリを作成するには、API メソッド (フィルター、Where など) を使用するだけでなく、これらのメソッドの引数としてラムダ式も使用します .Where(x => x > 3) (C# LINQ)。コンパイラはラムダをバイトコードに変換します。データ構造を基になるデータ ソースに変換できるように、API はデータ構造 (式ツリー) を構築する必要があります。基本的に、これを行うにはコンパイラが必要です。

免責事項 1: ラムダを実行するプロキシ オブジェクトを作成する方法があるかもしれませんが、演算子をオーバーロードしてデータ構造を生成します。これにより、実際の LINQ よりもわずかにパフォーマンスが低下します (実行時間とコンパイル時間)。そのようなライブラリが可能かどうかはわかりません。おそらく、ScalaQuery ライブラリも同様のアプローチを使用しています。

免責事項 2: Scala 言語は、式ツリーを取得できるように、ラムダを検査可能なオブジェクトとして実際に提供できる可能性があります。これにより、Scala のラムダ機能が C# のラムダ機能と同等になります。おそらく、ScalaQuery ライブラリーはこの仮想機能を使用しています。

編集2:少し掘り下げました。ScalaQuery はライブラリ アプローチを使用し、一連の演算子をオーバーロードして実行時にツリーを生成するようです。私は Scala の用語に精通しておらず、記事の複雑な Scala コードを読むのに苦労しているため、詳細については完全にはわかりません: http://szeiger.de/blog/2008/12/21/a-type-safe -database-query-dsl-for-scala/

クエリで使用またはクエリから返されるすべてのオブジェクトと同様に、テーブルはそれが表す値の型でパラメーター化されます。これは常に個々の列型のタプルであり、この場合は整数と文字列です (Int の代わりに java.lang.Integer を使用していることに注意してください。これについては後で詳しく説明します)。この点で、SQuery (私が今名前を付けたように) は LINQ よりも HaskellDB に近いです。なぜなら、Scala (ほとんどの言語と同様) は実行時に式の AST にアクセスできないからです。LINQ では、データベース内の値と列の実際の型を使用してクエリを記述し、実行時にクエリ式の AST を SQL に変換できます。このオプションがないと、Table や Column などのメタオブジェクトを使用して、これらから独自の AST を構築する必要があります。

確かに非常にクールなライブラリ。将来的には、それにふさわしい愛を受けて、実際に本番環境に対応できるツールになることを願っています.

于 2010-12-06T12:10:04.530 に答える
4

おそらくhttp://scalaquery.org/のようなものが必要です。SQLのみであることを除いて、@Stilgarの回答が示唆することとまったく同じです。

于 2010-12-06T12:10:41.203 に答える
1

http://squeryl.org/をチェックしてください

于 2010-12-06T21:48:58.583 に答える