Wątek przeniesiony 2021-01-25 09:48 z C# i .NET przez cerrato.

Złożone zapytanie czy procedura?

0

Cześć,
Buduję sobie aplikację w ASP .NET Core korzystając z EF Core (Code First). O tyle o ile proste zapytania wyciągające pełne obiekty po id czy listę wszystkich obiektów udało mi się ogarnąć poprzez repozytoria, gdzie umieszczam metody w LINQ tak mam teraz dość złożony case.

Aplikacja służy do budowania diety przez użytkownika:

  1. użytkownik dodaje nową dietę, a w niej kolejne dni
  2. dni składają się z posiłków
  3. posiłki składają się z produktów i ich ilości

Chciałbym dodać funkcjonalność generowania listy zakupów dla użytkownika, na podstawie wybranych dni oraz ilości tych dni wpisanych w inputa na froncie (kolumna ilość dni nie znajduje się w bazie). Na początku myślałem aby wykonać to w kodzie w jakiejś metodzie, której pętla iteruje najpierw po dniach, później po posiłkach, a następnie po produktach i sumuje wartości. Porzuciłem tą koncepcję, ponieważ wydaje się to być przekombinowane aby w pętli dodawać ilości kilkudziesięciu różnych produktów.

Mam gotowe zapytanie do bazy, ale chcę je przerobić na procedurę i wykorzystać ją w kodzie. Problem w tym, że nie wiem jak uwzględnić daną z frontu (ilość dni) i zawrzeć ją w zapytaniu skoro nie znajduje się w bazie. Wcześniej budowałem jedynie zapytania, to pierwsza procedura w moim kodzie. Prośba o pomoc.

Poniżej zapytanie SQL, z którego ma powstać procedura i dodatkowo ma uwzględniać ilość danych dni podanych przez użytkownika z frontu:

SELECT 
	P.CategoryId,
	MP.ProductId,
	SUM(MP.Quantity) AS 'Ilość'
  FROM [MealAppDB].[dbo].[DayDiets] DD
  RIGHT JOIN [MealAppDB].[dbo].[DayDietMeals] DDM
  ON DDM.DietDayId = DD.Id
  RIGHT JOIN [MealAppDB].[dbo].[MealProducts] MP
  ON MP.MealId = DDM.MealId
  RIGHT JOIN [MealAppDB].[dbo].[Products] P
  ON P.Id = MP.ProductId
  WHERE DD.ID IN (36,68, 69)
  GROUP BY P.CategoryId, MP.ProductId

A to część bazy wykorzystana w zapytaniu:
screenshot-20210125091332.png

0

Jak już, to funkcja zwracająca tabelę (Programability->Functions->Table-valued Functions). Procedura wykonuje operacje, ale nie zwraca żadnych informacji.

W parametrach funkcji SQL można podać dowolne wartości. W SQL każda zmienna ma nazwę zaczynającą się od @.

0

@andrzejlisek: czy na pewno procedura nic nie zwraca? pracowałem z procedurami w jednej firmie i podawałem do niej dane wejściowe, a także odbierałem obiekt na wyjściu.

1

Nie lepiej view? Masz u siebie tylko jedno zapytanie, filtrować je będziesz mógł łatwo po stronie C# dodając .Where() w linq, wypisz-wymaluj zastosowanie view.
SP moim zdaniem są użyteczne w takich miejscach, gdzie wykonujesz kilka zapytań, mieszając elementy CRUD i/lub umieszczając jakąś logikę (możliwie prostą), a funkcje z kolei są do obchodzenia pewnych problemów.

BTW nie stosuj nigdzie polskich nazw, kolumna Ilość -> Count, Sum, Amount, Quantity.

0
Krispekowy napisał(a):

@andrzejlisek: czy na pewno procedura nic nie zwraca? pracowałem z procedurami w jednej firmie i podawałem do niej dane wejściowe, a także odbierałem obiekt na wyjściu.

Funkcja musi coś zwrócić, procedura może.

0

@ŁF: A czy w podejściu CodeFirst w EntityFramework można utworzyć View? Pytam ciągnąc wątek, choć pewnie gdzieś na stacku czy w google znajdę odpowiedź

0

Dziwne podejście. "Mogę znaleźć samodzielnie i wiem o tym, ale i tak zapytam".
https://stackoverflow.com/questions/7461265/how-to-use-views-in-code-first-entity-framework

5

Jesteś pewny, że wolisz utworzyć procedurę/funkcję od zapytania, które umieścisz "w kodzie"?
Osobiście nigdy nie byłem zwolennikiem procedur, kursorów i innych tworów bazodanowych. Czasami, gdy efektywność jest bardzo ważna to jest to dobre rozwiązanie, ale ma niestety dużo wad, których trzeba być swiadomym:

  • konieczność utrzymania zarówno bazy danych jak i kodu.
  • utrudniony proces debugowania.
  • utrudnione wdrażanie nowych osób w projekt.
  • w przypadku triggerów po dłuższym czasie można zapomnieć o ich istnieniu.

Są to dość mocne punkty, które moim zdaniem trzeba rozważyć zanim umieścimy jakikolwiek kod po stronie bazy danych.

0

Próbuję wytworzyć zapytanie do bazy, ale coś chyba jest nie do końca tak jak powinno, agreguje mi quantity wg kategorii, zamiast kategorii i produktów...

            var query = dbContext.DayDiets
                .Join(dbContext.DayDietMeals, dd => dd.Id, ddm => ddm.DietDayId, (dd, ddm) =>
                new
                {
                    MealId = ddm.MealId
                })
                .Join(dbContext.MealProducts, ddm => ddm.MealId, mp => mp.MealId, (ddm, mp) =>
                new
                {
                    ProductId = mp.ProductId,
                    Quantity = mp.Quantity
                })
                .Join(dbContext.Products, mp => mp.ProductId, p => p.Id, (mp, p) =>
                new
                {
                    CategoryId = p.CategoryId,
                    ProductId = mp.ProductId,
                    ProductName = p.ProductName,
                    Quantity = mp.Quantity
                })
                .Join(dbContext.ProductCategories, p => p.CategoryId, pc => pc.Id, (p, pc) =>
                new
                {
                    CategoryId = p.CategoryId,
                    ProductId = p.ProductId,
                    ProductName = p.ProductName,
                    Quantity = p.Quantity,
                    CategoryName = pc.Name
                })
                .ToList()
                .GroupBy(a => new { a.CategoryName, a.ProductName })
                .Select(s => new { Quantity = s.Sum(q=>q.Quantity) });

1 użytkowników online, w tym zalogowanych: 0, gości: 1