강력한 클라이언트 측 쿼리 API를 사용하려고합니다. 클라이언트는 쿼리를 실행할 테이블과 조건을 쿼리에 지정할 수 있습니다. 물론 이것이 본격적인 LINQ 또는 SQL 로의 대체가 아니기 때문에 JS 클라이언트가 조인없이 테이블에서 복잡한 쿼리를 만들 수 있습니다.SqlProvider에서 리플렉션을 통해 데이터베이스 컨텍스트에서 테이블을 복구하는 방법은 무엇입니까?
이제 대부분은 다음과 같이 수행됩니다. 클라이언트는 JSON-serialized Predicate
(JSON.NET과 deserialize)을 보내면 쉽게 쿼리로 작성할 수 있습니다.
module Query =
open System.Linq
open FSharp.Data.Sql.Common
open FSharpComposableQuery
type Predicate =
| All
| Greater of string * System.IComparable
| GreaterEq of string * System.IComparable
| Lesser of string * System.IComparable
| LesserEq of string * System.IComparable
| Equal of string * obj
| Diff of string * obj
| And of Predicate * Predicate
| Or of Predicate * Predicate
| Not of Predicate
let satisfies (table : IQueryable<SqlEntity>) =
<@ fun p -> query {
for c in table do
if p c
then yield c
} @>
let rec eval t =
match t with
| All -> <@ fun _ -> true @>
| Greater (column, n) -> <@ fun (c : SqlEntity) -> c.GetColumn column > n @>
| GreaterEq (column, n) -> <@ fun c -> c.GetColumn column >= n @>
| Lesser (column, n) -> <@ fun c -> c.GetColumn column < n @>
| LesserEq (column, n) -> <@ fun c -> c.GetColumn column <= n @>
| Equal (column, n) -> <@ fun c -> c.GetColumn column = n @>
| Diff (column, n) -> <@ fun c -> c.GetColumn column <> n @>
| And (p1, p2) -> <@ fun c -> (%eval p1) c && (%eval p2) c @>
| Or (p1, p2) -> <@ fun c -> (%eval p1) c || (%eval p2) c @>
| Not p -> <@ fun c -> not((%eval p) c) @>
let predicate = Or (Equal ("myColumn", "myValue"), Equal ("myColumn", "myOtherValue"))
let t = query {
for c in <someDataProvidedTable> do
select (c :> SqlEntity)
}
let result = query { yield! (%satisfies t) (%eval predicate) } |> Seq.toArray
module DataLayer =
open FSharp.Data.Sql
open FSharp.Data.Sql.Common
let [<Literal>] ConnectionString = "Data Source=" + __SOURCE_DIRECTORY__ + @"/db.sqlite3;Version=3"
type Sql = SqlDataProvider<
ConnectionString = ConnectionString,
DatabaseVendor = Common.DatabaseProviderTypes.SQLITE,
IndividualsAmount = 1000,
UseOptionTypes = true >
let ctx = Sql.GetDataContext()
let db = ctx.Maint
매개 변수화하는 데 남은 것은 테이블입니다. DataLayer.db
에는 my 테이블과 동일한 테이블 객체가 있고 my 함수는 이러한 테이블 객체를 허용합니다. 하지만 클라이언트가 테이블을 문자열로 보낼 수있게하려면 DataLayer.db
에서 테이블을 검색해야합니다.
이제는 문자열에서 표 객체까지 사전을 사용하여이를 해결할 수 있다는 것을 알고 있습니다. 하지만 그렇게되면 전체 구조가 덜 유용해질 것입니다 (우리는 외부 DSL로부터 스키마와 클라이언트를 생성하고 있습니다). 물론, DataLayer.db.GetType().InvokeMethod
시도했지만 매개 변수가 무엇인지 상관없이 다음 예외가 발생합니다.
System.MissingMethodException: Method 'FSharp.Data.Sql.Runtime.SqlDataContext.FsmIssue' not found.
at System.RuntimeType.InvokeMember (System.String name, System.Reflection.BindingFlags bindingFlags, System.Reflection.Binder binder, System.Object target, System.Object[] providedArgs, System.Reflection.ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, System.String[] namedParams) [0x008a0] in <dca3b561b8ad4f9fb10141d81b39ff45>:0
at System.Type.InvokeMember (System.String name, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object target, System.Object[] args) [0x00000] in <dca3b561b8ad4f9fb10141d81b39ff45>:0
at <StartupCode$FSI_0062>[email protected]() [0x0001a] in <906a7cff96cb466bbad0babb35abf8de>:0
at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00038] in <dca3b561b8ad4f9fb10141d81b39ff45>:0
Stopped due to error
누구든지 나를 도와 줄 수 있습니까?
예외는 무엇입니까? – Asti
방금 예외를 포함하도록 게시물을 편집했습니다. – YuriAlbuquerque