Mam ten błąd w tym wyrażeniu linq:
var naleznosci = (from nalTmp in db.Naleznosci
where nalTmp.idDziecko == idDziec
select new Payments
(
nalTmp.Dziecko.Imie,
nalTmp.Dziecko.Nazwisko,
nalTmp.Miesiace.Nazwa,
nalTmp.Kwota,
nalTmp.RodzajeOplat.NazwaRodzajuOplaty,
nalTmp.RodzajeOplat.TypyOplat.NazwaTypuOplaty,
nalTmp.DataRozliczenia,
nalTmp.TerminPlatnosci
)).ToList();
Masz pomysł, jak rozwiązać ten problem? Próbuję z dowolną kombinacją wyrażeń ...: /
c#
linq-to-entities
netmajor
źródło
źródło
Odpowiedzi:
bez dodatkowych informacji na temat `` Płatności '' to niewiele pomoże, ale zakładając, że chcesz utworzyć obiekt Płatności i ustawić niektóre jego właściwości na podstawie wartości kolumn:
var naleznosci = (from nalTmp in db.Naleznosci where nalTmp.idDziecko == idDziec select new Payments { Imie = nalTmp.Dziecko.Imie, Nazwisko = nalTmp.Dziecko.Nazwisko, Nazwa= nalTmp.Miesiace.Nazwa, Kwota = nalTmp.Kwota, NazwaRodzajuOplaty = nalTmp.RodzajeOplat.NazwaRodzajuOplaty, NazwaTypuOplaty = nalTmp.RodzajeOplat.TypyOplat.NazwaTypuOplaty, DataRozliczenia = nalTmp.DataRozliczenia, TerminPlatnosci = nalTmp.TerminPlatnosci, }).ToList();
źródło
Jeśli nadal chcesz używać konstruktora do inicjowania, a nie właściwości (czasami to zachowanie jest pożądane do celów inicjowania), wylicz zapytanie, wywołując
ToList()
lubToArray()
, a następnie użyjSelect(…)
. W ten sposób użyje LINQ to Collections, a to ograniczenie polegające na braku możliwości wywołania konstruktora z parametrami wSelect(…)
zniknie.Twój kod powinien więc wyglądać mniej więcej tak:
var naleznosci = db.Naleznosci .Where(nalTmp => nalTmp.idDziecko == idDziec) .ToList() // Here comes transfer to LINQ to Collections. .Select(nalImp => new Payments ( nalTmp.Dziecko.Imie, nalTmp.Dziecko.Nazwisko, nalTmp.Miesiace.Nazwa, nalTmp.Kwota, nalTmp.RodzajeOplat.NazwaRodzajuOplaty, nalTmp.RodzajeOplat.TypyOplat.NazwaTypuOplaty, nalTmp.DataRozliczenia, nalTmp.TerminPlatnosci )) .ToList();
źródło
ToX()
do tego, użyjAsEnumerable()
.Po tym, jak sam napotkałem ten błąd, pomyślałem, że dodam, że jeśli
Payment
typ to astruct
, napotkasz również ten sam błąd, ponieważstruct
typy nie obsługują konstruktorów bez parametrów.W takim przypadku konwersja
Payment
do klasy i użycie składni inicjatora obiektu rozwiąże problem.źródło
DateTime
(która jest strukturą) w moim zapytaniu, co powoduje ten sam błąd. wypakowanie go do lokalnej zmiennej naprawiło to za mnie. Dzięki za wskazówkę dotyczącą struktury.Jeśli jesteś podobny do mnie i nie chcesz wypełniać swoich właściwości dla każdego budowanego zapytania, istnieje inny sposób rozwiązania tego problemu.
var query = from orderDetail in context.OrderDetails join order in context.Orders on order.OrderId equals orderDetail.orderId select new { order, orderDetail };
W tym momencie masz IQueryable zawierający anonimowy obiekt. Jeśli chcesz wypełnić swój niestandardowy obiekt konstruktorem, możesz po prostu zrobić coś takiego:
return query.ToList().Select(r => new OrderDetails(r.order, r.orderDetail));
Teraz twój niestandardowy obiekt (który przyjmuje dwa obiekty jako parametr) może wypełnić twoje właściwości według potrzeb.
źródło
Najpierw unikałbym rozwiązania z
from .... select new Payments { Imie = nalTmp.Dziecko.Imie, .... }
Wymaga to pustego konstruktora i ignoruje hermetyzację, więc mówisz, że new Payments () jest prawidłową płatnością bez żadnych danych, ale zamiast tego obiekt musi mieć co najmniej wartość i prawdopodobnie inne wymagane pola w zależności od Twojej domeny.
Lepiej mieć konstruktora dla wymaganych pól, ale przynosić tylko potrzebne dane:
from .... select new { Imie = nalTmp.Dziecko.Imie, Nazwisko = nalTmp.Dziecko.Nazwisko .... } .ToList() // Here comes transfer to LINQ to Collections. .Select(nalImp => new Payments ( nalTmp.Imie,//assume this is a required field ........... ) { Nazwisko = nalTmp.Nazwisko //optional field }) .ToList();
źródło
Możesz spróbować zrobić to samo, ale używając metod rozszerzania. Jaki jest dostawca bazy danych?
var naleznosci = db.Naleznosci .Where<TSource>(nalTmp => nalTmp.idDziecko == idDziec) .Select<TSource, TResult>( delegate(TSource nalTmp) { return new Payments ( nalTmp.Dziecko.Imie, nalTmp.Dziecko.Nazwisko, nalTmp.Miesiace.Nazwa, nalTmp.Kwota, nalTmp.RodzajeOplat.NazwaRodzajuOplaty, nalTmp.RodzajeOplat.TypyOplat.NazwaTypuOplaty, nalTmp.DataRozliczenia, nalTmp.TerminPlatnosci ); }) .ToList();
źródło
Wystarczy przed stwierdzeniem .. rzeczywista jest zapisywana jako zapytanie, to nie jest jeszcze spełnione. Po wywołaniu grasz z obiektami, a następnie możesz użyć w zapytaniu konstruktora innego niż domyślny.
ToList()
DbSet
Select
DbSet
ToList()
Nie jest to najbardziej efektywny sposób pod względem czasu użytkowania, ale jest to opcja w małych zestawach.
źródło
tak, spróbuj tego w ten sposób ....
var naleznosci = (from nalTmp in db.Naleznosci where nalTmp.idDziecko == idDziec select new Payments() { Dziecko.Imie, Dziecko.Nazwisko, Miesiace.Nazwa, Kwota, RodzajeOplat.NazwaRodzajuOplaty, RodzajeOplat.TypyOplat.NazwaTypuOplaty, DataRozliczenia, TerminPlatnosci }).ToList();
spowoduje to odświeżenie obiektu Payment przy użyciu konstruktora bez parametrów, a następnie zainicjuje właściwości wymienione w nawiasach klamrowych
{ }
źródło
()
w Payemnts nie jest potrzebna, więc można ją wybrać „select new Payments {// init values}”Oprócz wyżej wymienionych metod możesz również przeanalizować go jako kolekcję Enumerable, na przykład:
(from x in table .... ).AsEnumerable() .Select(x => ...)
Ma to również tę dodatkową zaletę, że ułatwia życie podczas tworzenia anonimowego obiektu, na przykład:
(from x in tableName select x.obj) .Where(x => x.id != null) .AsEnumerable() .Select(x => new { objectOne = new ObjectName(x.property1, x.property2), parentObj = x }) .ToList();
Pamiętając jednak, że analizowanie kolekcji jako Enumerable wciąga ją do pamięci, więc może wymagać dużych zasobów! Należy zachować ostrożność.
źródło
Ponadto, jeśli chcesz użyć konstruktora z wieloma obiektami do zainicjowania, możesz otrzymać błąd, jeśli Linq nie zwróci żadnych wartości.
Więc możesz zrobić coś takiego:
(from x in table_1 join y in table_2 on x.id equals y.id select new { val1 = x, val2 = y }) .DefaultIfEmpty() .ToList() .Select(a => new Val_Constructor(a.val1 != null ? a.val1 : new Val_1_Constructor(), a.val2 != null ? a.val2 : new Val_2_Constructor())) .ToList();
źródło
Przepraszam, że spóźniłem się na imprezę, ale po znalezieniu tego pomyślałem, że powinno się to udostępnić, ponieważ jest to najczystsza, najszybsza i oszczędzająca pamięć implementacja, jaką znalazłem.
Dostosowując się do twojego przykładu, napisałbyś:
public static IQueryable<Payments> ToPayments(this IQueryable<Naleznosci> source) { Expression<Func<Naleznosci, Payments>> createPayments = naleznosci => new Payments { Imie = source.Dziecko.Imie, Nazwisko = source.Dziecko.Nazwisko, Nazwa= source.Miesiace.Nazwa, Kwota = source.Kwota, NazwaRodzajuOplaty = source.RodzajeOplat.NazwaRodzajuOplaty, NazwaTypuOplaty = source.RodzajeOplat.TypyOplat.NazwaTypuOplaty, DataRozliczenia = source.DataRozliczenia, TerminPlatnosci = source.TerminPlatnosci, }; return source.Select(createPayments); }
Wielkie zalety tutaj (jak wskazał Damien Guard w komentarzach pod linkiem) to:
var foo = createPayments(bar);
Możliwe użycie przez, jak również użycie przez myIQueryable.ToPayments ().źródło
Miałem dzisiaj ten sam problem i moje rozwiązanie było podobne do tego, które wymienił Yoda, jednak działa tylko z płynną składnią.
Dostosowanie mojego rozwiązania do twojego kodu: dodałem następującą metodę statyczną do klasy obiektu
/// <summary> /// use this instead of a parameritized constructor when you need support /// for LINQ to entities (fluent syntax only) /// </summary> /// <returns></returns> public static Func<Naleznosci, Payments> Initializer() { return n => new Payments { Imie = n.Dziecko.Imie, Nazwisko = n.Dziecko.Nazwisko, Nazwa = n.Miesiace.Nazwa, Kwota = n.Kwota, NazwaRodzajuOplaty = n.RodzajeOplat.NazwaRodzajuOplaty, NazwaTypuOplaty = n.RodzajeOplat.TypyOplat.NazwaTypuOplaty, DataRozliczenia = n.DataRozliczenia, TerminPlatnosc = n.TerminPlatnosci }; }
a następnie zaktualizowałem zapytanie podstawowe do następującego:
var naleznosci = (from nalTmp in db.Naleznosci where nalTmp.idDziecko == idDziec select new Payments.Initializer());
Jest to logicznie równoważne z rozwiązaniem Jamesa Manninga, ale ma tę zaletę, że przenosi nadmiar inicjalizacji elementu członkowskiego do obiektu transferu klasy / danych
Uwaga: Początkowo używałem bardziej opisowych nazw niż „Initializer”, ale po przejrzeniu, jak go używam, stwierdziłem, że „Initilizer” był wystarczający (przynajmniej do moich celów).
Uwaga końcowa:
Po wymyśleniu tego rozwiązania początkowo myślałem, że udostępnienie tego samego kodu i dostosowanie go do pracy również ze składnią zapytań będzie proste. Nie wierzę już, że tak jest. Myślę, że jeśli chcesz móc używać tego typu skróconej konstrukcji, potrzebujesz metody dla każdego (zapytania, płynnego) biegłego, jak opisano powyżej, która może istnieć w samej klasie obiektów.
W przypadku składni zapytania wymagana byłaby metoda rozszerzenia (lub inna metoda spoza używanej klasy bazowej). (ponieważ składnia zapytania chce obsługiwać IQueryable zamiast T)
Oto próbka tego, czego użyłem, aby w końcu uruchomić to dla składni zapytań. (Yoda już to załatwił, ale myślę, że użycie mogłoby być jaśniejsze, ponieważ nie dostałem tego na początku)
/// <summary> /// use this instead of a parameritized constructor when you need support /// for LINQ to entities (query syntax only) /// </summary> /// <returns></returns> public static IQueryable<Payments> Initializer(this IQueryable<Naleznosci> source) { return source.Select( n => new Payments { Imie = n.Dziecko.Imie, Nazwisko = n.Dziecko.Nazwisko, Nazwa = n.Miesiace.Nazwa, Kwota = n.Kwota, NazwaRodzajuOplaty = n.RodzajeOplat.NazwaRodzajuOplaty, NazwaTypuOplaty = n.RodzajeOplat.TypyOplat.NazwaTypuOplaty, DataRozliczenia = n.DataRozliczenia, TerminPlatnosc = n.TerminPlatnosci }; }
i użytkowania
var naleznosci = (from nalTmp in db.Naleznosci where nalTmp.idDziecko == idDziec select nalTmp).Initializer().ToList();
źródło
Chociaż jest późno na odpowiedź, może pomóc komuś w potrzebie. Ponieważ LINQ to entity nie obsługuje konstrukcji obiektów bez parametrów. Jednak metody projekcji dla IEnumerable .
Więc przed wyborem, po prostu przekonwertuj swój IQueryable na IEnumerable , używając tego kodu:
var result = myContext.SomeModelClass.AsEnumerable().Select(m => m.ToString());
Będzie działać dobrze. Jednak utraci to oczywiście zalety zapytań natywnych.
źródło
IQueryable<SqlResult> naleznosci = (from nalTmp in db.Naleznosci where nalTmp.idDziecko == idDziec select new Payments { Imie = nalTmp.Dziecko.Imie, Nazwisko = nalTmp.Dziecko.Nazwisko, Nazwa= nalTmp.Miesiace.Nazwa, Kwota = nalTmp.Kwota, NazwaRodzajuOplaty = nalTmp.RodzajeOplat.NazwaRodzajuOplaty, NazwaTypuOplaty = nalTmp.RodzajeOplat.TypyOplat.NazwaTypuOplaty, DataRozliczenia = nalTmp.DataRozliczenia, TerminPlatnosci = nalTmp.TerminPlatnosci, }); Repeater1.DataSource = naleznosci.ToList(); Repeater1.DataBind(); public class SqlResult { public string Imie { get; set; } public string Nazwisko { get; set; } ... }
źródło