Преобразование сложного sql хранимого процесса в linq - PullRequest
0 голосов
/ 24 января 2011

Я использую Linq to Sql и у меня есть сохраненный процесс, который не будет генерировать класс. Хранимая процедура извлекает данные из нескольких таблиц в набор результатов плоских файлов.

Количество возвращаемых данных должно быть как можно меньше, количество обратных обращений к серверу Sql должно быть ограничено, а объем обработки на стороне сервера должен быть ограничен, как для проекта ASP.NET MVC .

Итак, я пытаюсь написать Linq to 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

У кого-нибудь есть еще предложения?

1 Ответ

1 голос
/ 25 января 2011

Судя по внешнему виду этого SQL и кода, я бы не стал превращать его в запросы LINQ. Это просто запутает логику и, возможно, у вас уйдут дни, чтобы ее исправить.

Если SQLMetal не генерирует его должным образом, рассматривали ли вы возможность использования ExecuteQuery метода DataContext для возврата списка элементов, которые вы ищете?

Предполагая, что ваш 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 использует правильные параметры SQLParameters , если вы используете кривые, а не просто соединяете строки самостоятельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...