لماذا أحصل على خطأ في وقت الترجمة في استعلام LINQ هذا؟

StackOverflow https://stackoverflow.com/questions/20354027

  •  25-08-2022
  •  | 
  •  

سؤال

أحصل على خطأ في وقت الترجمة عند تجميع الكود أدناه ولا يمكنني معرفة السبب:

العلاقات كثيرة للعديد من العلاقات

 var contacts = groups_to_querry
                .SelectMany(x => x.Contacts)
                .Where(x => x.ID == Guid.Empty)
                .SelectMany(p => p.ContactDetails)
                .Where(x => x.ID == Guid.Empty)
                .SelectMany(x => x.Contacts);  //This line gives me a compile time error 
                //Error : The Type argumetns for method 'System.Linq.Enumerable.SelectMany<TSource,Tresult>
                //(System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource,
                //System.Collections.Generic.IEnumerable<TResult>>)' cannot be infrred from the usage.  
                //Try specifying the type arguments explicitly
هل كانت مفيدة؟

المحلول

المرة الثانية التي تتصل بها .SelectMany(x => x.Contacts), ، أنت تعمل حاليًا مع مجموعة من ContactDetails. من المشكوك فيه أنك ستتمكن من استخدامها SelectMany عليه. ستحتاج إلى استخدام Select في حين أن.

SelectMany يتم استخدامه عندما تريد تحديد مجموعات متعددة من العناصر ووضعها في واحدة IEnumerable. Select يستخدم في الحقول الفردية. بما أنك تعمل مع كائنات من النوع ContactDetail (وهو ما أفترض أنه يمكن أن يكون لديه اتصال واحد فقط) ، ستحتاج إلى استخدام Select

تحرير: هنا ما تفعله باختصار ، خطوة بخطوة:

groups_to_querry.SelectMany(x => x.Contacts): من جميع المجموعات التي أريد الاستعلام عن جميع جهات الاتصال العديدة. كل مجموعة لديها العديد من جهات الاتصال ، لذا ضعها جميعًا في واحدة IEnumerable مجموعة من النوع Contact

.Where(x => x.ID == Guid.Empty): ... ولكن فقط تلك الاتصالات مع معرف فارغ

.SelectMany(p => p.ContactDetails): ثم حدد كل جهات الاتصال هذه 'ContactDetails. يحتوي كل جهة اتصال على العديد من ContactDetails ، لذا ضعها جميعًا في واحدة IEnumerable مجموعة من النوع ContactDetail

.Where(x => x.ID == Guid.Empty): ... ولكن فقط تلك contactDetails مع معرف فارغ

.SelectMany(x => x.Contacts);: الآن حدد كل من جهات اتصال ContactDetails. ومع ذلك ، نظرًا لأن المترجم يعلم أن هناك علاقة فردية بين جهات الاتصال و contactDetails (وليس العكس

نصائح أخرى

أقوم بتفسير استعلامك المقصود على أنه "من مجموعات متعددة من جهات الاتصال ، وحدد جميع جهات الاتصال التي تحتوي على معرف = Guid.Empty وأيضًا تفاصيل تحتوي جميعها على ID = Guid.Empty".

الطريقة التي يتم بها تفسير الكود الخاص بك بالفعل هي "من جميع جهات الاتصال التي لها Guid.Empty ، وتحديد جميع التفاصيل التي لها Guid.Empty ، ومن هذه التفاصيل حدد جميع جهات الاتصال". المشكلة الأولى هي أن ينتهي بك الأمر إلى الاختيار من التفاصيل. هذا يعني النهائي SelectMany يجب أن يكون Select, ، لان x.Contacts هنا يشير إلى العلاقة العديدة إلى واحد من التفاصيل إلى جهات الاتصال.

المشكلة الثانية هي أن النتيجة ستحتوي على تكرارات لجهات الاتصال ، لأن جهة الاتصال نفسها يتم تضمينها لكل التفاصيل. ما يجب أن تفعله بدلاً من ذلك هو تصفية جهات الاتصال مباشرة بناءً على مجموعات التفاصيل الخاصة بهم ، مثل هذا:

groups_to_query
.SelectMany(g => g.Contacts)
.Where(c => c.ID == Guid.Empty)
.Where(c => c.ContactDetails.All(d => d.ID == Guid.Empty))

لاحظ أن هذا سيختار أيضًا جهات اتصال تحتوي على تفاصيل صفر ، وهو سلوك مختلف عن استعلامك ، لذلك لست متأكدًا مما إذا كان هذا ما تريده. يمكنك إضافة مرشح آخر ل ContactDetails.Any() ان لم.

يحرر: نظرًا لأنك تستخدم إطار الكيان ، فربما لن يعمل ما سبق. قد تحتاج إلى تحديد التفاصيل في مسمة فرعية ثم تصفية في الذاكرة بعد تنفيذها:

var queryResult =
    groups_to_query
    .SelectMany(g => g.Contacts)
    .Where(c => c.ID == Guid.Empty)
    .Select(c => new {
        contact = c,
        detailIDs = c.ContactDetails.Select(d => d.ID)
    }).ToList();

var contacts =
    queryResult
    .Where(r => r.detailIDs.All(id => id == Guid.Empty))
    .Select(r => r.contact);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top