9

T/SQL またはストアド プロシージャの記述の代わりとして Type Provider 機能を使用するための F# 3 の評価。

let summary = 
  query {   for dsm in db.DistributorSalesMaster do
            join c in db.CustomerMain on 
              ( dsm.CustomerId = c.CustomerId)
            join cal in db.Calendar on
              ( dsm.InvoiceDate =? cal.TheDate)
            join dsd in db.DistributorSalesDetail on
              ( dsm.SalesId = dsd.SalesId)             
            where (dsm.InvoiceDate >= Convert.ToDateTime("2010-12-01") 
                && dsm.InvoiceDate <= Convert.ToDateTime("2011-11-30")
                && c.MainDistributorId=1s
                && c.DistributorId=1s
                && c.CustomerId = 159M
                && cal.APYear?=2011
                )

            groupValBy dsd.InvoiceQuantity ca.APYear into g
            select (g.Key,g.Count())}

期待どおりに動作します。DB コンテキスト ログは、これを次のように確認します。

    SELECT COUNT(*) AS [Item2], [t2].[APYear] AS [Item1]
    FROM [dbo].[DistributorSalesMaster] AS [t0]
    INNER JOIN [dbo].[CustomerMain] AS [t1] ON [t0].[customerId] = [t1].[customerId]
    INNER JOIN [dbo].[Calendar] AS [t2] ON ([t0].[invoiceDate]) = [t2].[TheDate]
    INNER JOIN [dbo].[DistributorSalesDetail] AS [t3] ON [t0].[salesId] = [t3].[salesId]
    WHERE ([t0].[invoiceDate] >= @p0) AND ([t0].[invoiceDate] <= @p1) AND ([t1].[mainDistributorId] = @p2) AND ([t1].[distributorId] = @p3) AND ([t1].[customerId] = @p4) AND ([t2].[APYear] = @p5)
    GROUP BY [t2].[APYear]
    -- @p0: Input DateTime (Size = -1; Prec = 0; Scale = 0) [12/1/2010 12:00:00 AM]
    -- @p1: Input DateTime (Size = -1; Prec = 0; Scale = 0) [11/30/2011 12:00:00 AM]
    -- @p2: Input SmallInt (Size = -1; Prec = 0; Scale = 0) [1]
    -- @p3: Input SmallInt (Size = -1; Prec = 0; Scale = 0) [1]
    -- @p4: Input Decimal (Size = -1; Prec = 29; Scale = 0) [159]
    -- @p5: Input Int (Size = -1; Prec = 0; Scale = 0) [2011]
    -- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.17929

ただし、次のことを試みます。

let summary = 
   query {   for dsm in db.DistributorSalesMaster do
             join c in db.CustomerMain on 
                ( dsm.CustomerId = c.CustomerId)
             join cal in db.Calendar on
                ( dsm.InvoiceDate =? cal.TheDate)
             join dsd in db.DistributorSalesDetail on
                ( dsm.SalesId = dsd.SalesId)             
             where (dsm.InvoiceDate >= Convert.ToDateTime("2010-12-01") 
                    && dsm.InvoiceDate <= Convert.ToDateTime("2011-11-30")
                    && c.MainDistributorId=1s
                    && c.DistributorId=1s
                    && c.CustomerId = 159M
                    && cal.APYear?=2011
                    )

             groupValBy dsd.InvoiceQuantity (cal.APYear, cal.APMonth) into g              
             select (g.Key,g.Count())}

DB コンテキスト ログを次のように生成します。

System.NotSupportedException: The member 'System.Tuple`2[System.Nullable`1[System.Int32],System.Nullable`1[System.Int32]].Item1' has no supported translation to SQL.
   at System.Data.Linq.SqlClient.PostBindDotNetConverter.Visitor.VisitMember(SqlMember m)
   at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
   .
   .
   .
   at System.Data.Linq.DataQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at Microsoft.FSharp.Collections.SeqModule.ToArray[T](IEnumerable`1 source)
   at FSI_0002.showDataGrid[a](IEnumerable`1 x) in D:\Work\Tests\FP\FSharpVS2012\FSharpVS2012\IPFS3ZDPTests.fsx:line 21
   at <StartupCode$FSI_0024>.$FSI_0024.main@()
Stopped due to error

groupValBy複数の列 ( cal.APYear、 )にしようとしていますcal.APMonth。Data Type Provider で SQL に変換されないようです。

結果を達成する他の方法をいくつか見つけましたが、DB コンテキスト ログは、結合のみが SQL に変換され、残りgroupBy/groupValBy処理はメモリ内で行われることを示唆しています。これは私が望んでいないことです。メモリ内ではなくDBでクエリ式全体を変換して実行したい。私の探求を明確にしたことを願っています。

この点に関するヘルプやガイドをいただければ幸いです。

4

1 に答える 1

4

AnonymousObjectを使用する必要があります。以下が機能するはずです。

let summary = 
   query {   for dsm in db.DistributorSalesMaster do
             join c in db.CustomerMain on 
                ( dsm.CustomerId = c.CustomerId)
             join cal in db.Calendar on
                ( dsm.InvoiceDate =? cal.TheDate)
             join dsd in db.DistributorSalesDetail on
                ( dsm.SalesId = dsd.SalesId)             
             where (dsm.InvoiceDate >= Convert.ToDateTime("2010-12-01") 
                    && dsm.InvoiceDate <= Convert.ToDateTime("2011-11-30")
                    && c.MainDistributorId=1s
                    && c.DistributorId=1s
                    && c.CustomerId = 159M
                    && cal.APYear?=2011
                    )

             let key = AnonymousObject<_,_>(cal.APYear, cal.APMonth)

             groupValBy dsd.InvoiceQuantity key into g              
             select (key.Item1, key.Item2, g.Count())}
于 2013-06-10T00:06:28.133 に答える