Linq do SQL

0

Cześć, robię system (ta część o której mowa to WebAPI .Net Core 2), w którym nie używam Entity Framework (używam go jedynie do logowania użytkowników). To nie jest prosty crud, więc sam klepię SQLe.

Ale doszedłem do miejsca, którego się obawiałem. Mam zwrócić listę obiektów na podstawie przekazanego warunku. I teraz mam kilka możliwości:

  1. Wyposażyć serwis w szereg metod, które będą właściwie robiły to samo
  2. Wyposażyć serwis w metodę, która przyjmie string - będzie to warunek WHERE do dodania w zapytaniu SQL i wywołany z poziomu kontrolera - to rozwiązanie wydaje mi się mało eleganckie
  3. Wyposażyć serwis w metodę, która przyjmie jakiś predykat za pomocą którego zwróci odpowiednie dane. I to wydaje mi się najbardziej rozsądne podejście (zresztą na tej zasadzie działają ORMy).

Tylko teraz pojawia się problem. W związku z tym, że to jest .Net Core 2, nie mogę użyć System.Data.Linq. Więc albo użyję w tym miejscu też ORMa, co byłoby jednak nieco głupie, albo znajdę inny sposób na przetłumaczenie predykatu LINQ do SQL.

Wyczytałem w necie wiele rozwiązań robiących z DataReader IEnumerable, jednak to ma jeden główny minus - pobiera wszystkie dane z bazy :) Tego oczywiście chcę uniknąć. Więc jakie są możliwości żeby to zrobić bez żadnego typowego ORMa? Aktualnie posługuję się bazą MariaDb i ADO .NET.

1

No ale na czym konkretnie polega problem?

Możesz wydobyć nazwę property z expression np. taką funkcją (pisane z palca, nie wiem czy działa):

public static string GetPropertyName<T>(Expression<Func<T, object>> expression)
{
        var lambda = (LambdaExpression)expression;
	var body = lambda.Body as MemberExpression;

	if (body == null)
	{
		body = ((UnaryExpression)expression.Body).Operand as MemberExpression;
	}

	return body.Member.Name;
}

Doklej to porządnie to zapytania sql i będzie działać. Pod warunkiem oczywiście, że nazwa kolumny zgadza się z nazwą właściwości.

0

Hmm, wychodzi że to jednak nie jest tak proste i oczywiste. Bazując na tym, co napisałeś, pokombinowałem trochę i wyszło mi coś takiego:

public static string GetExprAsString<T>(Expression<Func<T, object>> expression)
        {
            UnaryExpression operation = (UnaryExpression)expression.Body;
            BinaryExpression operand = (BinaryExpression)operation.Operand;
            MemberExpression left = (MemberExpression)operand.Left;
            var right = operand.Right;


            return left.Member.Name + operand.NodeType + right;
        }

To wymaga jeszcze szlifu, żeby operand.NodeType zwrócił poprawny operator, tj. "<" zamiast "LessThan". Jednak zadziała tylko dla najprostszej sytuacji w stylu:

service.GetPerson(p => p.Name == "Janek");

czyli porównanie jednej właściwości. Jeśli chodzi o or'y, czy and'y, no to sprawa się komplikuje. A nie daj Boże przyjdzie do głowy coś jeszcze ciekawszego. Nie wiem, czy będę w to brnął, chociaż z ciekawości spróbowałbym napisać taki własny mechanizm. Oczywiście, jak zwykle "brak czasu" :)

Więc może zna ktoś jakieś gotowce, które spełniają założenia? Tak po prawdzie to nie potrzebuję, żeby mi to wywaliło pełnego SQLa.
Wystarczą mi tylko warunki, np:

"Name = 'Janek' or Name = 'Bogdan'"

1

Prawdopodobnie łatwiej byłoby, gdyby API wyglądało tak: service.GetPerson().Where(p => p.Name, Operator.Equals, "Janek").Or(p => p.Name, Operator.Equals, "Bogdan").Single();

I oczywiście, że sprawa się komplikuje. Dlatego właśnie nikt tego nie pisze sam tylko używa ORMów. ;)

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