Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 ASP .NET Entities странный выбор первых N записей таблицы по какому то признаку  [new]
Уппит Сергей
Member

Откуда:
Сообщений: 12
Добрый день. Столкнулся на первый взгляд с проходной проблемой. Кратко. Есть таблица товаров. Каждый товар принадлежит брэнду и есть поле код брэнда. Надо всего лишь выбрать топ 50 товаров данного брэнда. Итого пишем такой код:

public List<Product> GetByBrandID(int brandId, int top)
        {
            try
            {
                        #region Это отладка запроса
                        IQueryable<Product> query = en.Products.Take(top).Where(p => p.BrandID == brandId);
                        string str = Utils.Utils.ToTraceString(query);

                        IQueryable<Product> query2 = en.Products.Where(p => p.BrandID == brandId).Take(top);
                        string str2 = Utils.Utils.ToTraceString(query);
                        #endregion

                        return en.Products.Take(top).Where(p => p.BrandID == brandId && p.DeleteDate == null).ToList();
                    }
            }
            catch
            {
                return new List<Product>();
            }
        }


Собственно говоря задача сам запрос вот: en.Products.Take(top).Where(p => p.BrandID == brandId && p.DeleteDate == null).ToList();

Теперь самое интересное!

Дело в том, что товаров данного брэнда ВСЕГО 10 а мы берем 50. Итог - пустая выборка.
Начал копать. Решил посмотреть, а какой запрос собственно говоря генерируется то. Нашел в интернете такие функции, может кому будут полезны:

public static string ToTraceString<T>(IQueryable<T> query)
        {
            var internalQueryField = query.GetType().GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Where(f => f.Name.Equals("_internalQuery")).FirstOrDefault();

            var internalQuery = internalQueryField.GetValue(query);

            var objectQueryField = internalQuery.GetType().GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Where(f => f.Name.Equals("_objectQuery")).FirstOrDefault();

            var objectQuery = objectQueryField.GetValue(internalQuery) as System.Data.Entity.Core.Objects.ObjectQuery<T>;

            return ToTraceStringWithParameters<T>(objectQuery);
        }


        public static string ToTraceStringWithParameters<T>(System.Data.Entity.Core.Objects.ObjectQuery<T> query)
        {
            System.Text.StringBuilder sb = new StringBuilder();

            string traceString = query.ToTraceString() + Environment.NewLine;

            foreach (var parameter in query.Parameters)
            {
                traceString += parameter.Name + " [" + parameter.ParameterType.FullName + "] = " + parameter.Value + "\n";
            }

            return traceString;
        }


Соответственно в вернем коде я их и вызвал:

 #region Это отладка запроса
                        IQueryable<Product> query = en.Products.Take(top).Where(p => p.BrandID == brandId);
                        string str = Utils.Utils.ToTraceString(query);

                        IQueryable<Product> query2 = en.Products.Where(p => p.BrandID == brandId).Take(top);
                        string str2 = Utils.Utils.ToTraceString(query);
 #endregion


А вот и итог. Обратите внимание, что я директиву Take вызывал как до так и после блока Where, чтобы убедиться. Результат одинаков.

SELECT 
    [Limit1].[ID] AS [ID], 
    [Limit1].[Articul] AS [Articul], 
    [Limit1].[Name] AS [Name], 
    [Limit1].[Description] AS [Description], 
    [Limit1].[BrandID] AS [BrandID], 
    [Limit1].[Image] AS [Image], 
    [Limit1].[DeleteDate] AS [DeleteDate], 
    [Limit1].[ShowByDefault] AS [ShowByDefault], 
    [Limit1].[ArticulToSearch] AS [ArticulToSearch]
    FROM ( SELECT TOP (50) [c].[ID] AS [ID], [c].[Articul] AS [Articul], [c].[Name] AS [Name], [c].[Description] AS [Description], [c].[BrandID] AS [BrandID], [c].[Image] AS [Image], [c].[DeleteDate] AS [DeleteDate], [c].[ShowByDefault] AS [ShowByDefault], [c].[ArticulToSearch] AS [ArticulToSearch]
        FROM [dbo].[Products] AS [c]
    )  AS [Limit1]
    WHERE ([Limit1].[BrandID] = @p__linq__0) AND (@p__linq__0 IS NOT NULL)
p__linq__0 [System.Int32] = 34


Тоесть, если я правильно понимаю, сначала берется топ 50 записей товаров, а они уже фильтруются по коду брэнда. Это капец!

Конечно я могу написать хранимую процедуру, чтобы все это обойти, но я хочу понять, что я делаю не так. Почему, вроде логичная конструкция в Linq на деле приводит к такому кривому запросу.

Прошу помощи у знающих людей. Как правильно сформировать запрос?
31 июл 15, 09:57    [17958571]     Ответить | Цитировать Сообщить модератору
 Re: ASP .NET Entities странный выбор первых N записей таблицы по какому то признаку  [new]
Glory
Member

Откуда:
Сообщений: 104751
Уппит Сергей
Как правильно сформировать запрос?

Это зависит от версии вашего MSSQL
31 июл 15, 10:00    [17958584]     Ответить | Цитировать Сообщить модератору
 Re: ASP .NET Entities странный выбор первых N записей таблицы по какому то признаку  [new]
o-o
Guest
вам наверное сюда:
ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM
31 июл 15, 10:01    [17958587]     Ответить | Цитировать Сообщить модератору
 Re: ASP .NET Entities странный выбор первых N записей таблицы по какому то признаку  [new]
Уппит Сергей
Member

Откуда:
Сообщений: 12
Glory,

А причем здесь версия МSSQL, если текст запроса генерируется в программе. Запрос четко показывает, берем топ 50 а потом фильтруем.
31 июл 15, 10:06    [17958616]     Ответить | Цитировать Сообщить модератору
 Re: ASP .NET Entities странный выбор первых N записей таблицы по какому то признаку  [new]
Glory
Member

Откуда:
Сообщений: 104751
Уппит Сергей
А причем здесь версия МSSQL

Притом, что здесь форум по МSSQL.
И для составления запроса нужна версия сервера.
31 июл 15, 10:07    [17958624]     Ответить | Цитировать Сообщить модератору
 Re: ASP .NET Entities странный выбор первых N записей таблицы по какому то признаку  [new]
churupaha
Member

Откуда: Краснодар
Сообщений: 1015
Уппит Сергей
IQueryable<Product> query = 
     en.Products
     .Take(top) 
     .Where(p => p.BrandID == brandId);



Оба extension метода Top/Where, скорее всего, возвращают IQueryable<...>, потому можно так

Уппит Сергей
IQueryable<Product> query = 
     en.Products
     .Where(p => p.BrandID == brandId)
     .Take(top);



Проверять лень, пробуй.
31 июл 15, 10:12    [17958656]     Ответить | Цитировать Сообщить модератору
 Re: ASP .NET Entities странный выбор первых N записей таблицы по какому то признаку  [new]
churupaha
Member

Откуда: Краснодар
Сообщений: 1015
ой, слишком по диагонали прочитал вопрос.
31 июл 15, 10:15    [17958677]     Ответить | Цитировать Сообщить модератору
 Re: ASP .NET Entities странный выбор первых N записей таблицы по какому то признаку  [new]
o-o
Guest
Уппит Сергей
А причем здесь версия МSSQL, если текст запроса генерируется в программе.

ага, и программа эта совсем не называется SQL Server.
поэтому вам явно не сюда
31 июл 15, 10:17    [17958689]     Ответить | Цитировать Сообщить модератору
 Re: ASP .NET Entities странный выбор первых N записей таблицы по какому то признаку  [new]
churupaha
Member

Откуда: Краснодар
Сообщений: 1015
Уппит Сергей,

раз оба генерят одно и тоже - похоже на баг orm-ки.
31 июл 15, 10:17    [17958692]     Ответить | Цитировать Сообщить модератору
 Re: ASP .NET Entities странный выбор первых N записей таблицы по какому то признаку  [new]
Уппит Сергей
Member

Откуда:
Сообщений: 12
churupaha,

Каюсь. Сам допустил ошибку.
Правда, если поставить Take после, то получим другой, ПРАВИЛЬНЫЙ запрос:

SELECT TOP (50) 
    [Extent1].[ID] AS [ID], 
    [Extent1].[Articul] AS [Articul], 
    [Extent1].[Name] AS [Name], 
    [Extent1].[Description] AS [Description], 
    [Extent1].[BrandID] AS [BrandID], 
    [Extent1].[Image] AS [Image], 
    [Extent1].[DeleteDate] AS [DeleteDate], 
    [Extent1].[ShowByDefault] AS [ShowByDefault], 
    [Extent1].[ArticulToSearch] AS [ArticulToSearch]
    FROM [dbo].[Products] AS [Extent1]
    WHERE ([Extent1].[BrandID] = @p__linq__0) AND (@p__linq__0 IS NOT NULL)
p__linq__0 [System.Int32] = 34
31 июл 15, 10:18    [17958697]     Ответить | Цитировать Сообщить модератору
 Re: ASP .NET Entities странный выбор первых N записей таблицы по какому то признаку  [new]
Glory
Member

Откуда:
Сообщений: 104751
Уппит Сергей
Правда, если поставить Take после, то получим другой, ПРАВИЛЬНЫЙ запрос:

А MSSQL тут причем ?
31 июл 15, 10:19    [17958700]     Ответить | Цитировать Сообщить модератору
 Re: ASP .NET Entities странный выбор первых N записей таблицы по какому то признаку  [new]
Уппит Сергей
Member

Откуда:
Сообщений: 12
o-o,

Ну проблема решена. Сам дурак, когда добывал строки запроса.

А программа да, совсем не SQL сервер. Это интернет магазин, где есть библиотека работающая с SQL и применяющая довольно удобную технологию .Net Entities и именно этот фреймворк шлет запросы в СУБД. Поэтому от что это 2012, что 2014 версия и пр зависеть точно не будет. Слишком простой запрос получается.
31 июл 15, 10:21    [17958716]     Ответить | Цитировать Сообщить модератору
 Re: ASP .NET Entities странный выбор первых N записей таблицы по какому то признаку  [new]
o-o
Guest
Уппит Сергей
А программа да, совсем не SQL сервер. Это интернет магазин, где есть библиотека работающая с SQL и применяющая довольно удобную технологию .Net Entities и именно этот фреймворк шлет запросы в СУБД.

ну так смотрите второй пост в этой теме, я вас куда и отправляю
31 июл 15, 10:32    [17958806]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить