Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2 3 4 5 6   вперед  Ctrl      все
 Передача лямбды в репозиторий. Где ошибка?  [new]
Maksimka-27
Member

Откуда:
Сообщений: 14
Разбираю Pro Entity Framework Core 2 for ASP.NET Core MVC замечательного автора Adam Freeman.

Строится модель, например:
public class Product
{
public long Id { get; set; }
public string Name { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public decimal PurchasePrice { get; set; }
}

Строим класс репозитория (объявление контекста и интерфейса- опускаю):

public class DataRepository : IRepository
    {
        
        private DataContext context;

        public DataRepository(DataContext ctx) => context = ctx;

       public IEnumerable<Product> ProductsChoose(Func<Product, bool> func)
          {
            IEnumerable<Product> p = context.Products
                    .Where(func)
                    .ToList();    
            return p;   
           }


В контроллере идет вызов:
     IEnumerable<Product> p = repository.ProductsChoose(x => x.RetailPrice < 100);


При этом формируется SQL:
Executed DbCommand (31ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [p].[Id], [p].[CategoryId], [p].[Name], [p].[PurchasePrice], [p].[RetailPrice]
FROM [Products] AS [p]


Но если я переписываю репозиторий ():

public IEnumerable<Product> ProductsChoose(Func<Product, bool> func)
          {
            IEnumerable<Product> p = context.Products
                    .Where(x => x.RetailPrice < 100)
                    .ToList();    
            return p;   }


[то получаю вполне ожидаемый код, который ведет отбор на сервере базы данных:
SELECT [x].[Id], [x].[CategoryId], [x].[Name], [x].[PurchasePrice], [x].[RetailPrice]
FROM [Products] AS [x]
WHERE [x].[RetailPrice] < 100.0


При этом результаты вывода - одинаковые.
Почему передача лямбды в репозиторий приводит к фильтрации строк на стороне EF а не SQL?
Где я ошибаюсь?
9 апр 19, 06:52    [21856638]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
L.Otujktd
Member

Откуда:
Сообщений: 69
Maksimka-27,
Скорее всего проблема в отложенном выполнении, реальное преобразование в запрос происходит на момент вычисления всей цепочки, ваш внешний func не может заинжектиться корректно, что логично. Надо смотреть в доке как разбирается Linq
9 апр 19, 08:25    [21856688]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 20532
пробуй
ProductsChoose(Expression<Func<Product, bool>> func)
9 апр 19, 08:58    [21856706]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
Maksimka-27
Member

Откуда:
Сообщений: 14
Shocker.Pro,

Помогло, Спасибо!!!!
9 апр 19, 10:03    [21856764]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
Maksimka-27
Разбираю Pro Entity Framework Core 2 for ASP.NET Core MVC замечательного автора Adam Freeman.
хмм...
А MS со своим кодом ниже в пику ему делает свои справки и демки?
dotnet ef dbcontext scaffold xxxxxxxxxx
И получаем вместо репозитория класс XXXContext.cs
?
9 апр 19, 10:53    [21856841]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 20532
Фримен упирает на модульное тестирование, поэтому интерфейс для репозитория в примере - вполне в его стиле.
9 апр 19, 10:56    [21856847]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
Shocker.Pro,
Спс.
9 апр 19, 11:02    [21856857]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
L.Otujktd
Member

Откуда:
Сообщений: 69
Shocker.Pro
пробуй
ProductsChoose(Expression<Func<Product, bool>> func)

+1
9 апр 19, 11:46    [21856911]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
hVostt
Member

Откуда:
Сообщений: 15822
Maksimka-27
IEnumerable<Product>


IQueryable
9 апр 19, 12:41    [21856991]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
hVostt
Maksimka-27
IEnumerable<Product>



IQueryable
тогда
.ToList();
будет лишним?
9 апр 19, 12:58    [21857014]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
hVostt
Member

Откуда:
Сообщений: 15822
Petro123
.ToList();
будет лишним?


делать ToList() и возвращать IEnumerable сродни тому, как плюнуть в лицо :)

хотя бы ICollection, хотя желательно IReadOnlyCollection

касательно озвученной проблемы, правильно решается с помощью паттерна спецификаций, например:

https://enterprisecraftsmanship.com/2016/02/08/specification-pattern-c-implementation/
9 апр 19, 14:14    [21857160]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
hVostt
делать ToList() и возвращать IEnumerable сродни тому, как плюнуть в лицо :)
)))
9 апр 19, 15:02    [21857266]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 20532
hVostt
делать ToList() и возвращать IEnumerable сродни тому, как плюнуть в лицо :)
Кстати, слышал как-то формулу - параметр метода должен быть максимально абстрактного типа, результат - максимально конкретного. Скажи, гуру, ты согласен с этой формулой?

То есть, в данном случае, вернуть прямо таки List<>. Если потребителю нужен ICollection - он сам выполнит приведение. А может ему понадобится непосредственно функционал листа.
9 апр 19, 15:07    [21857277]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
Shocker.Pro
Если потребителю нужен ICollection - он сам выполнит приведение.
с этим не согласен.
Возвращать нужно то что просят выше. Чтобы 200 вызовов не приводить и кода не добавлять.
9 апр 19, 15:13    [21857284]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
hVostt
Member

Откуда:
Сообщений: 15822
Shocker.Pro
Кстати, слышал как-то формулу - параметр метода должен быть максимально абстрактного типа, результат - максимально конкретного. Скажи, гуру, ты согласен с этой формулой?


Главное не путать абстракцию с семантикой.

IEnumerable -- это бесконечная последовательность, в качестве которой может выступать как коллекция, так и генератор, поэтому он не является абстракцией коллекции.

самая максимальная абстракция коллекции в C# это IReadOnlyCollection.

Shocker.Pro
То есть, в данном случае, вернуть прямо таки List<>.


Ни в коем случае. List это реализация. Вообще самые злостные крайности джунов это возвращать IEnumerable, или List. Ругаю очень за такое.

Shocker.Pro
Если потребителю нужен ICollection - он сам выполнит приведение. А может ему понадобится непосредственно функционал листа.


Я говорю конкретно про контракты.
9 апр 19, 23:59    [21857805]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
hVostt
Ни в коем случае. List это реализация. Вообще самые злостные крайности джунов это возвращать IEnumerable, или List. Ругаю очень за такое.
не понял. Я налево и направо возвращаю.
А что делать, если наверху правят эту коллекцию?
10 апр 19, 07:48    [21857905]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
ViPRos
Member

Откуда:
Сообщений: 9568
Petro123
hVostt
Ни в коем случае. List это реализация. Вообще самые злостные крайности джунов это возвращать IEnumerable, или List. Ругаю очень за такое.
не понял. Я налево и направо возвращаю.
А что делать, если наверху правят эту коллекцию?

надо вернуть метаданные - адрес памяти, длина блока памяти
а там пусть как хотят так и интерпретируют
а то всякие там коллекции и т.д. не кошерны
10 апр 19, 09:52    [21857992]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
ViPRos
надо вернуть метаданные - адрес памяти, длина блока памяти
в Net есть Pointer или *p
?
10 апр 19, 10:12    [21858013]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
hVostt
Member

Откуда:
Сообщений: 15822
Petro123
не понял. Я налево и направо возвращаю.
А что делать, если наверху правят эту коллекцию?


если коллекция может правиться, то ICollection.
если к этому нужен индексированный доступ, то IList.

контракты должны быть максимально абстрактными, но не нарушать семантику.
а то можно вообще везде object возвращать, чё мелочиться-то? :)
10 апр 19, 11:35    [21858104]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
stenford
Member

Откуда: урал
Сообщений: 2759
hVostt
IQueryable

руки отрубать за такое надо. Логика запросов расползется по всем слоям убив поддерживаемость и производительность
10 апр 19, 12:59    [21858207]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
hVostt
Member

Откуда:
Сообщений: 15822
stenford
hVostt
IQueryable

руки отрубать за такое надо. Логика запросов расползется по всем слоям убив поддерживаемость и производительность


серьёзно? за много лет мне ещё никто не доказал и не показал, что там "убивается" в поддержке и производительности

IQueryable это абстрактный контракт слоя работы с данными. ни чем не отличается от +100500 других костылей и способов, просто у отдельных людей откуда-то возникает панический страх, который они не могут ни понять, ни объяснять.

работай со слоем доступа к данным из слоя логики, не тащи на клиентский слой, в чём проблемы?

это прям когнитивный диссонанс. видишь как человек боится юзать IQueryable, потом смотришь а он там прокидывает IEnumerable или вообще List -- дабл фейспалм.
10 апр 19, 13:06    [21858222]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
stenford
Member

Откуда: урал
Сообщений: 2759
hVostt
серьёзно? за много лет мне ещё никто не доказал и не показал, что там "убивается" в поддержке и производительности

IQueryable это абстрактный контракт слоя работы с данными. ни чем не отличается от +100500 других костылей и способов, просто у отдельных людей откуда-то возникает панический страх, который они не могут ни понять, ни объяснять.

работай со слоем доступа к данным из слоя логики, не тащи на клиентский слой, в чём проблемы?

это прям когнитивный диссонанс. видишь как человек боится юзать IQueryable, потом смотришь а он там прокидывает IEnumerable или вообще List -- дабл фейспалм.

то, что ты чего-то там в своей жизни не видел не влияет на то, как эти вещи работают, если у тебя создан репозиторий - то логика запросов должна содержаться в нем по указанным выше причинам, в простых случаях он не нужен и никто не мешает работать с базой из слоя логики, а кашу и репозитория и логики запросов в нескольких слоях лепят только студенты на первых годах своей работы пока не поднаберутся опыта
10 апр 19, 13:32    [21858261]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
hVostt
Member

Откуда:
Сообщений: 15822
stenford
то, что ты чего-то там в своей жизни не видел не влияет на то, как эти вещи работают, если у тебя создан репозиторий - то логика запросов должна содержаться в нем по указанным выше причинам, в простых случаях он не нужен и никто не мешает работать с базой из слоя логики, а кашу и репозитория и логики запросов в нескольких слоях лепят только студенты на первых годах своей работы пока не поднаберутся опыта


абосолютно ни о чём. IQueryable это абстракция. ни чем не хуже любых созданных вами кривых поделок, и не надо тут залечивать про кашу, не умеете -- не варите.

про репозитории вида god queries object уже писалось не раз, обсуждалось. то, что вы слыхом про это не слыхивали, проблемы только ваши.
10 апр 19, 15:40    [21858453]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
hVostt
Member

Откуда:
Сообщений: 15822
stenford
на первых годах своей работы пока не поднаберутся опыта


как я вижу, многим и десятки лет опыта ничего не дают. как лепят свои унылые поделки, которые освоили на студенческих примерах, так и продолжают лепить до посинения.
10 апр 19, 15:41    [21858455]     Ответить | Цитировать Сообщить модератору
 Re: Передача лямбды в репозиторий. Где ошибка?  [new]
love_bach
Member

Откуда:
Сообщений: 515
Maksimka-27
Разбираю Pro Entity Framework Core 2 for ASP.NET Core MVC замечательного автора Adam Freeman.

Строится модель, например:
public class Product
{
public long Id { get; set; }
public string Name { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public decimal PurchasePrice { get; set; }
}

Строим класс репозитория (объявление контекста и интерфейса- опускаю):

public class DataRepository : IRepository
    {
        
        private DataContext context;

        public DataRepository(DataContext ctx) => context = ctx;

       public IEnumerable<Product> ProductsChoose(Func<Product, bool> func)
          {
            IEnumerable<Product> p = context.Products
                    .Where(func)
                    .ToList();    
            return p;   
           }


В контроллере идет вызов:
     IEnumerable<Product> p = repository.ProductsChoose(x => x.RetailPrice < 100);


При этом формируется SQL:
Executed DbCommand (31ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [p].[Id], [p].[CategoryId], [p].[Name], [p].[PurchasePrice], [p].[RetailPrice]
FROM [Products] AS [p]


Но если я переписываю репозиторий ():

public IEnumerable<Product> ProductsChoose(Func<Product, bool> func)
          {
            IEnumerable<Product> p = context.Products
                    .Where(x => x.RetailPrice < 100)
                    .ToList();    
            return p;   }


[то получаю вполне ожидаемый код, который ведет отбор на сервере базы данных:
SELECT [x].[Id], [x].[CategoryId], [x].[Name], [x].[PurchasePrice], [x].[RetailPrice]
FROM [Products] AS [x]
WHERE [x].[RetailPrice] < 100.0


При этом результаты вывода - одинаковые.
Почему передача лямбды в репозиторий приводит к фильтрации строк на стороне EF а не SQL?
Где я ошибаюсь?


а нафига вообще такой репозиторий?
12 апр 19, 19:12    [21860831]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2 3 4 5 6   вперед  Ctrl      все
Все форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM Ответить