LINQ से Entities तक केवल पैरामीटर रहित कन्स्ट्रक्टर और इनिशियलाइज़र समर्थित हैं


132

मुझे इस 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();

किसी भी विचार कैसे इस समस्या को हल? मैं अभिव्यक्ति के किसी भी संयोजन के साथ कोशिश करता हूं ...: /


1
क्या आप भुगतान वर्ग दिखा सकते हैं? या कम से कम ctor को यहाँ बुलाया जा रहा है, और विशेष रूप से यह कि क्या 8-परम ctor कॉल को 0-परम ctor कॉल के लिए सुरक्षित रूप से स्वैप किया जा सकता है और ऑब्जेक्ट पर 8 गुण सेट कर सकता है?
जेम्स मैनिंग

23
मुझे यह त्रुटि तब मिली जब मैं ऑब्जेक्ट के लिए एक क्लास के बजाय एक संरचना का उपयोग कर रहा था जो "नया था।"
हकीत

3
टीएल; डीआर बात यह है कि ईएफ-लाइनक्यू ईएफ प्रदाता को चुनिंदा बयान भेजने की कोशिश कर रहा है, अर्थात। इसे एसक्यूएल में परिवर्तित करें। EF-LINQ से बाहर निकलने के लिए, किसी भी ऑब्जेक्ट के निर्माण से पहले ToList () को कॉल करें।

जवाबों:


127

'भुगतान' के बारे में अधिक जानकारी के बिना यह बहुत मदद नहीं करता है, लेकिन यह मानकर कि आप भुगतान ऑब्जेक्ट बनाना चाहते हैं और स्तंभ मान के आधार पर इसके कुछ गुण सेट करते हैं:

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();

10
यह महान काम करता है, वर्ग के लिए एक खाली कंस्ट्रक्टर जोड़ना मत भूलना।
लाइव-लव

58
इस उत्तर को जोड़ने के लिए, आप इसे स्ट्रक्चर के साथ नहीं कर सकते हैं, केवल क्लासेस - मुझे यह पता लगाने में थोड़ा समय लगा!
naspinski

4
हां, मुझे लगता है कि टोनी का जवाब इस से बेहतर है क्योंकि यह वास्तव में तत्काल समस्या को हल करता है, जबकि यह एक भुगतान वर्ग की प्रकृति को बदलकर समस्या को रोकता है और संभवतः इसे अपरिवर्तनीय होने से रोकता है।
स्टीफन होल्ट

यह बदसूरत लग रहा है। EF6 के साथ कोई बेहतर तरीका?
टूलकिट

115

यदि आप अभी भी अपने निर्माता को आरंभीकरण के लिए उपयोग करना चाहते हैं, न कि गुणों के लिए (कभी-कभी यह व्यवहार आरंभिक उद्देश्यों के लिए वांछित होता है), तो क्वेरी को कॉल करके ToList()या ToArray()फिर उपयोग करें Select(…)। इस प्रकार यह LINQ टू कलेक्शंस का उपयोग करेगा और यह कि कंस्ट्रक्टर को मापदंडों के साथ कॉल करने में सक्षम नहीं होने की सीमा Select(…)समाप्त हो जाएगी।

तो आपका कोड कुछ इस तरह दिखना चाहिए:

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();

21
बस यह स्पष्ट करने के लिए कि यह क्यों काम करता है, मूल रूप से बताए गए कोड के साथ समस्या यह है कि एंटिटी फ्रेमवर्क, LINQ क्वेरी के बाकी हिस्सों के साथ SQL के माध्यम से कंस्ट्रक्टर कॉल को पास करने का प्रयास करता है, और निश्चित रूप से SQL के निर्माण के बारे में जाने का कोई रास्ता नहीं है। जटिल वस्तुओं! ToList () कॉल को सम्मिलित करने से आप एन्युमरेबल को एक अभी तक निष्पादित SQL क्वेरी से मेमोरी में ऑब्जेक्ट की ठोस सूची में ले जाते हैं, जिसे आप किसी भी तरह से हेरफेर कर सकते हैं।
स्टीफन होल्ट

19
इसके ToX()लिए उपयोग न करें , उपयोग करें AsEnumerable()
Rawling

1
.ToList () // यहां LINQ से कलेक्शन में ट्रांसफर आता है। वह रेखा है जो मेरे लिए समस्या का समाधान करती है।
राम

15
ज्ञात रहे कि यह db स्तर पर सभी कॉलमों का चयन करेगा जहाँ आम तौर पर यह केवल आवश्यक कॉलमों का चयन करेगा
Hugh Jeffner

4
इतना ही नहीं, लेकिन आप शायद कई गणना करने जा रहे हैं। मुझे यह समाधान पसंद नहीं है।
ब्लूबरन

47

केवल इस त्रुटि का सामना करने के बाद, मैंने सोचा कि मैं जोड़ूंगा कि यदि Paymentप्रकार एक है struct, तो आप भी उसी त्रुटि का सामना करेंगेstruct प्रकार पैरामीटर रहित निर्माणकर्ताओं का समर्थन नहीं करते हैं।

उस घटना में, Paymentएक वर्ग में कनवर्ट करना और ऑब्जेक्ट इनिशियललाइज़र सिंटैक्स का उपयोग करके समस्या को हल किया जाएगा।


इससे समस्या का समाधान हो जाता है। वास्तव में संरचना चयनकर्ता के साथ यह प्रश्न LINQ-2-SQL में समर्थित है और जब आप EntityFramework पर अपग्रेड कर रहे हैं तो यह एक समस्या है।
टॉमस क्यूब्स

मुझे स्ट्रक्चर से नफरत है। वे कभी नहीं करते कि मैं क्या चाहता हूं
सिमोन_विवर

DateTimeमेरी क्वेरी के अंदर एक (जो एक संरचना है) बनाया गया, जिसके परिणामस्वरूप वही त्रुटि होती है। एक स्थानीय चर के लिए इसे निकालकर मेरे लिए तय किया। संरचना संकेत के लिए धन्यवाद।
लकीलीकी

20

यदि आप मेरे जैसे हैं और आपके द्वारा बनाई जा रही प्रत्येक क्वेरी के लिए अपनी संपत्ति को आबाद नहीं करना चाहते हैं, तो इस मुद्दे को हल करने का एक और तरीका है।

var query = from orderDetail in context.OrderDetails
            join order in context.Orders on order.OrderId equals orderDetail.orderId
            select new { order, orderDetail };

इस बिंदु पर आपके पास एक IQueryable है जिसमें एक अनाम वस्तु है। यदि आप अपने कस्टम ऑब्जेक्ट को एक कंस्ट्रक्टर के साथ आबाद करना चाहते हैं तो आप बस कुछ ऐसा कर सकते हैं:

return query.ToList().Select(r => new OrderDetails(r.order, r.orderDetail));

अब आपकी कस्टम ऑब्जेक्ट (जो पैरामीटर के रूप में दो ऑब्जेक्ट लेती है) आपके गुणों को आवश्यकतानुसार बदल सकती है।


यह मेरे लिए काम किया और सबसे साफ समाधान बन गया। जिन लोगों ने कंस्ट्रक्टर को खत्म करने और शुरुआती सिंटैक्स का उपयोग करने का सुझाव दिया है, उनके पास कंस्ट्रक्टर के भीतर तर्क नहीं होना चाहिए। यह एकमात्र समय है जब मैं किसी वस्तु के लिए गुणों को आबाद करने के लिए कंस्ट्रक्टरों पर झुक जाता हूं। साझा करने के लिए धन्यवाद।
बोनज़ ०२४

9

पहले मैं समाधान के साथ बचना होगा

from ....
select new Payments
{
  Imie = nalTmp.Dziecko.Imie,
  ....
}

इसके लिए एक खाली कंस्ट्रक्टर की आवश्यकता होती है और इनकैप्सुलेशन को अनदेखा करता है, इसलिए आप कह रहे हैं कि नया भुगतान () बिना किसी डेटा के एक वैध भुगतान है, लेकिन इसके बजाय आपके डोमेन के आधार पर ऑब्जेक्ट का कम से कम मूल्य और संभवतः अन्य आवश्यक फ़ील्ड होना चाहिए।

आवश्यक फ़ील्ड के लिए एक निर्माता होना बेहतर है लेकिन केवल आवश्यक डेटा लाएं:

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();

यह कम बुराई है।
चलक १

मैं भी कुछ इस तरह से पसंद करता हूं। मैं Tuple का उपयोग करने के लिए बांधने की कोशिश कर रहा था, लेकिन Tuple में पैरामीटर कम कंस्ट्रक्टर नहीं है। मैंने एक अनाम वस्तु पॉप्युलेट की और फिर टपल का चयन किया।
Tchaps

एन्कैप्सुलेशन और डोमेन को गले लगाने के लिए एक
7:30 बजे inrandomwetrust

2

आप ऐसा करने की कोशिश कर सकते हैं, लेकिन विस्तार के तरीकों का उपयोग करके। डेटाबेस उपयोग के प्रदाता क्या है?

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();

2

बस से पहले बयान .. वास्तविक एक प्रश्न के रूप में सहेजा जाता है, यह अभी तक पूरा नहीं किया है। कॉल करने के बाद आप ऑब्जेक्ट्स के साथ खेल रहे हैं, और फिर आप क्वेरी में एक गैर-डिफ़ॉल्ट कंस्ट्रक्टर का उपयोग कर सकते हैं।ToList()DbSetSelectDbSetToList()

सबसे कुशल तरीका उपयोग-समय वार नहीं है, लेकिन यह छोटे सेट पर एक विकल्प है।


1

सुनो, इस तरह से कोशिश करो ...।

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();

यह एक पैरामीटर्सलेस कंस्ट्रक्टर का उपयोग करके आपके भुगतान ऑब्जेक्ट को नया कर देगा, और फिर घुंघराले ब्रेस के अंदर सूचीबद्ध गुणों को इनिशियलाइज़ करेगा { }


3
()Payemnts में FYI करने की आवश्यकता नहीं है, इसलिए यह `नए भुगतानों का चयन करें {// init मान}
PostMan

अब मेरे पास त्रुटि है: एक संग्रह
इनिशलाइज़र के

सही - यदि आप एक प्रकार का भुगतान कर रहे हैं (भुगतान वर्ग के एक उदाहरण के बजाय), तो मुद का कोड ठीक होगा क्योंकि सेट करने के लिए गुणों का अर्थ होगा कि पढ़े जा रहे गुणों के नाम। चूंकि यह एक 'वास्तविक' वर्ग है, हालांकि, आपको यह निर्दिष्ट करने की आवश्यकता होगी कि कौन से गुण विभिन्न मूल्यों पर सेट हैं।
जेम्स मैनिंग 5

1

उपरोक्त तरीकों के अलावा, आप इसे एक संग्रहणीय संग्रह के रूप में भी पार्स कर सकते हैं, जैसे:

(from x in table
....
).AsEnumerable()
.Select(x => ...)

अनाम वस्तु का निर्माण करते समय जीवन को आसान बनाने का यह अतिरिक्त लाभ भी है, जैसे:

 (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();

हालाँकि, याद रखना कि एनुमरबल के रूप में एक संग्रह को पार्स करना, इसे मेमोरी में खींचता है, इसलिए यह संसाधन गहन हो सकता है! यहां सावधानी बरतनी चाहिए।


1

इसके अलावा, यदि आप कई ऑब्जेक्ट्स के साथ एक कंस्ट्रक्टर को इनिशियलाइज़ करना चाहते हैं, तो आपको Linq द्वारा कोई मान नहीं दिए जाने पर त्रुटि हो सकती है।

तो आप कुछ इस तरह से करना चाह सकते हैं:

(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();

1

पार्टी में देर से आने के लिए खेद है, लेकिन मुझे यह पता चलने के बाद , मैंने सोचा कि इसे साझा किया जाना चाहिए क्योंकि यह सबसे साफ, सबसे तेज और स्मृति-बचत कार्यान्वयन है जो मुझे मिल सकता है।

आपके उदाहरण के अनुकूल, आप लिखेंगे:

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);
}

यहाँ बड़े लाभ (जैसा कि डेमियन गार्ड ने लिंक पर टिप्पणियों में बताया है) हैं:

  • प्रत्येक घटना पर इनिशियलाइज़ेशन पैटर्न का उपयोग करने से आपको बचाता है।
  • उपयोग के माध्यम से और var foo = createPayments(bar);साथ ही myIQueryable.ToPayments () के माध्यम से उपयोग संभव है।

1

मुझे आज भी यही समस्या थी और मेरा समाधान योडा सूचीबद्ध के समान था, हालांकि यह केवल धाराप्रवाह वाक्य रचना के साथ काम करता है।

अपने कोड के लिए मेरे समाधान को अपनाना: मैंने ऑब्जेक्ट क्लास में निम्नलिखित स्टैटिक विधि जोड़ी

    /// <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
        };
    }

और फिर आधार क्वेरी को निम्न में अपडेट किया:

var naleznosci = (from nalTmp in db.Naleznosci
    where nalTmp.idDziecko == idDziec
    select new Payments.Initializer());

यह क्लास / डेटा ट्रांसफर ऑब्जेक्ट के लिए सदस्य प्रारंभ के ब्लोट को धकेलने के लाभ के साथ जेम्स मैनिंग के समाधान के लिए तार्किक रूप से समतुल्य है।

नोट: मूल रूप से मैं अधिक वर्णनात्मक नामों का उपयोग कर रहा था जो कि "इनिशियलाइज़र" था लेकिन मैं इसका उपयोग कैसे कर रहा था, इसकी समीक्षा करने के बाद, मैंने पाया कि "Initilizer" पर्याप्त था (कम से कम मेरे उद्देश्यों के लिए)।

अंतिम नोट:
इस समाधान के साथ आने के बाद, मैं मूल रूप से सोच रहा था कि एक ही कोड को साझा करना सरल होगा और इसे क्वेरी सिंटैक्स के लिए भी काम करना होगा। मैं अब ऐसा नहीं मानता हूं कि ऐसा होना चाहिए। मुझे लगता है कि यदि आप इस प्रकार के आशुलिपि निर्माण का उपयोग करने में सक्षम होना चाहते हैं, तो आपको प्रत्येक (क्वेरी, धाराप्रवाह) धाराप्रवाह के लिए एक विधि की आवश्यकता होगी जैसा कि ऊपर वर्णित है जो ऑब्जेक्ट क्लास में ही मौजूद हो सकता है।

क्वेरी सिंटैक्स के लिए एक एक्सटेंशन विधि (या बेस क्लास के बाहर कुछ विधि का उपयोग किया जा रहा है) की आवश्यकता होगी। (चूंकि क्वेरी सिंटैक्स T के बजाय एक IQueryable संचालित करना चाहता है)

यहाँ एक नमूना है जिसे मैंने अंततः क्वेरी सिंटैक्स के लिए काम करने के लिए उपयोग किया था। (योदा ने पहले ही इसे पकड़ लिया था लेकिन मुझे लगता है कि उपयोग स्पष्ट हो सकता है क्योंकि मुझे यह पहले नहीं मिला था)

/// <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
    };
}

और उपयोग

var naleznosci = (from nalTmp in db.Naleznosci
    where nalTmp.idDziecko == idDziec
    select nalTmp).Initializer().ToList();

पूर्णता के लिए क्वेरी सिंटैक्स के बारे में एक खंड जोड़ा जब मुझे महसूस हुआ कि मेरा प्रारंभिक उत्तर अच्छी तरह से विस्तारित नहीं हुआ है। @ सोडा की ऐवर क्वेरी सिंटैक्स के संबंध में शायद बेहतर है।
wode

0

हालांकि इसका उत्तर देने में देर हो चुकी है, फिर भी यह संकट में किसी की मदद कर सकता है। चूंकि LINQ से निकाय तक पैरामीटर-कम ऑब्जेक्ट निर्माण का समर्थन नहीं करते हैं। हालांकि, IEnumerable के लिए प्रक्षेपण के तरीके ।

इसलिए चयन से पहले, बस इस कोड का उपयोग करके अपने IQuery को IEnumerable में परिवर्तित करें :

var result = myContext.SomeModelClass.AsEnumerable().Select(m => m.ToString());

यह ठीक काम करेगा। हालांकि, यह निश्चित रूप से, देशी प्रश्नों के लाभों को ढीला करेगा।


0
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; }
        ...
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.