2011-01-24 19 views
0

私はLinqをSqlに使用しており、クラスを生成しないストアドプロシージャを持っています。ストアドプロシージャは、複数のテーブルのデータをフラットファイルの結果セットに描画します。複雑なSQLストアドプロシージャをlinqに変換

返されるデータ量はできるだけ小さくする必要があります.Sql Serverへのラウンドトリップ回数を制限する必要があります。また、ASP.NET MVCの場合と同じように、サーバー側の処理量を制限する必要がありますプロジェクト。

私はLinqをSql Queryに書くことを試みていますが、返されたデータを複製して制限することには苦労しています。これまでのところ、私はフラットファイルを返すが、リストの数を制限することはできないのですが、

SELECT AdShops.shop_id as ID, Users.image_url_75x75, AdShops.Advertised, 
    Shops.shop_name, Shops.title, Shops.num_favorers as hearts, Users.transaction_sold_count as sold, 
    (select sum(L4.num_favorers) from Listings as L4 where L4.shop_id = L.shop_id) as listings_hearts, 
    (select sum(L4.views) from Listings as L4 where L4.shop_id = L.shop_id) as listings_views, 
    L.title AS listing_title, L.price as price, L.listing_id AS listing_id, L.tags, L.materials, L.currency_code, 
    L.url_170x135 as listing_image_url_170x135, L.url AS listing_url, l.views as listing_views, l.num_favorers as listing_hearts 

FROM AdShops INNER JOIN 
    Shops ON AdShops.shop_id = Shops.shop_id INNER JOIN 
    Users ON Shops.user_id = Users.user_id INNER JOIN 
    Listings AS L ON Shops.shop_id = L.shop_id 

WHERE (Shops.is_vacation = 0 AND 
    L.listing_id IN 
    (
     SELECT listing_id 
     FROM (SELECT l2.user_id , l2.listing_id, RowNumber = ROW_NUMBER() OVER (PARTITION BY l2.user_id ORDER BY NEWID()) 
        FROM Listings l2 
          INNER JOIN (
          SELECT user_id 
          FROM Listings 
          GROUP BY 
            user_id 
          HAVING COUNT(*) >= 3 
          ) cnt ON cnt.user_id = l2.user_id 
       ) l2 
     WHERE l2.RowNumber <= 3 and L2.user_id = L.user_id 
    ) 
    ) 
ORDER BY Shops.shop_name 

今:

は、ここで私が変換しようとしているストアドプロシージャです。私がこだわっているのはここです:

Dim query As IEnumerable = From x In db.AdShops 
         Join y In (From y1 In db.Shops 
            Where y1.Shop_name Like _Search + "*" AndAlso y1.Is_vacation = False 
            Order By y1.Shop_name 
            Select y1) On y.Shop_id Equals x.shop_id 
         Join z In db.Users On x.user_id Equals z.User_id 
         Join l In db.Listings On l.Shop_id Equals y.Shop_id 
         Select New With { 
          .shop_id = y.Shop_id, 
          .user_id = z.user_id, 
          .listing_id = l.Listing_id 
          } Take 24 ' Fields ommitted for briefity... 

私は店あたり3つのリストのランダムなセットを選択すると仮定し、しかし私はこれを行う方法を確認していないラムダ式を使用する必要があるだろう。また、個々の店舗に対するフィールドを掲載するための連結合計をどこかに追加する必要があります。

誰でも意見はありますか?

UPDATE:

  1. 結果クラスラッパー:
 
    Public Class NewShops 
     Public Property Shop_id As Integer 
     Public Property listing_id As Integer 
     Public Property tl_listing_hearts As Integer? 
     Public Property tl_listing_views As Integer? 
     Public Property listing_creation As Date 
    End Class 
  1. LINQの+コード:

ここで私が見ています現在のソリューションです

 
Using db As New Ads.DB(Ads.DB.Conn) 
    Dim query As IEnumerable(Of IGrouping(Of Integer, NewShops)) = 
     (From x In db.AdShops 
     Join y In (From y1 In db.Shops 
        Where (y1.Shop_name Like _Search + "*" AndAlso y1.Is_vacation = False) 
        Select y1 
        Skip ((_Paging.CurrentPage - 1) * _Paging.ItemsPerPage) 
        Take (_Paging.ItemsPerPage)) 
       On y.Shop_id Equals x.shop_id 
     Join z In db.Users On x.user_id Equals z.User_id 
     Join l In db.Listings On l.Shop_id Equals y.Shop_id 
     Join lt In (From l2 In db.Listings _ 
        Group By id = l2.Shop_id Into Hearts = Sum(l2.Num_favorers), Views = Sum(l2.Views), Count() _ 
        Select New NewShops With {.tl_listing_views = Views, 
               .tl_listing_hearts = Hearts, 
               .Shop_id = id}) 
       On lt.Shop_id Equals y.Shop_id 
     Select New NewShops With {.Shop_id = y.Shop_id, 
            .tl_listing_views = lt.tl_listing_views, 
            .tl_listing_hearts = lt.tl_listing_hearts, 
            .listing_creation = l.Creation, 
            .listing_id = l.Listing_id 
            }).GroupBy(Function(s) s.Shop_id).OrderByDescending(Function(s) s(0).tl_listing_views) 

    Dim Shops as New Dictionary(Of String, List(Of NewShops)) 

    For Each item As IEnumerable(Of NewShops) In query 
     Shops.Add(item(0).shop_name, (From i As NewShops In item 
             Order By i.listing_creation Descending 
             Select i Take 3).ToList) 
    Next 
End Using 

他にも提案がありますか?

+3

私の考えは、なぜこれをしたいのですか? Linq2SQLはSQLを補完するものであり、SQLを補完するものではありません。 – leppie

+0

私が読んだことから、LinqはSQLのテーブルへのマッピングを行いました。私はstored_procをマッピングしようとしましたが、sqlmetalはエラーをスローします。簡単な方法があれば、私はそれをやって喜んでいるでしょう。 – Graeme

+0

sqlmetalのエラーは何ですか? – leppie

答えて

1

そのSQLとコードの外観から、私はLINQクエリに変換していません。それは単に論理を難読化し、おそらくそれを正しいものにする日数を取るでしょう。

SQLMetalが正しく生成しない場合は、DataContextExecuteQueryメソッドを使用して、後続のアイテムのリストを返すことを検討しましたか?

あなたが変換しようとしているあなたのSPROCがsp_complicatedと呼ばれ、あなたが陥る前にトリックに

Protected Class TheResults 
    Public Property ID as Integer 
    Public Property image_url_75x75 as String 
    '... and so on and so forth for all the returned columns. Be careful with nulls 
End Class 

'then, when you want to use it 

Using db As New Ads.DB(Ads.DB.Conn) 
    dim results = db.ExecuteQuery(Of TheResults)("exec sp_complicated {0}", _Search) 
End Using 

を行う必要があり、以下、それはへ感受性がありませんように、一つのパラメータで何かを取ると仮定するとSQLインジェクション。 L2SQL uses proper SQLParameters、squiggliesを使用していて、ストリングを自分自身で連結するだけではありません。

+0

これははるかに簡単です。上記のストアドプロシージャにページングを追加するにはどうすればよいですか? – Graeme

+0

私は完全にはわかりません。 Row_Numberと2つ以上のパラメータを使用すると思いますが、私は_years_のページングで遊んでいません。クイックグーグルは、ほとんどの人がCTEとRow_Numberを使用していると言っています - グーグル/ビンゴ "SQL Serverストアドプロシージャrow_numberページング"は開始するには良い場所になります –

+0

ダン...ありがとうございます... – Graeme

関連する問題