Возврат коллекции объектов, в которой свойство объектов соответствует любому свойству из другой коллекции объектов с использованием LINQ-to-Entities

Весь день ищу и не могу найти решение этой проблемы...

У меня есть EntityCollection из Communication объектов, каждый из которых имеет экземпляр объекта Intention (один к одному).

У меня также есть объект User, который имеет много экземпляров UserLocation EntityObjects (один ко многим)

  • Intention объекты имеют свойство UID.
  • UserLocation объектов имеют свойство LID.

  • Я хочу написать выражение LINQ, которое возвращает все объекты Communication, где свойство UID экземпляра Intention, связанного с объектом Communication, равно ЛЮБОМу свойству LID ЛЮБОГО экземпляра экземпляра UserLocation для объекта User.

я пробовал это

return _context.Communications.Where
(u => u.Intention.UID.Equals
(user.UserLocations.Select
(p => p.LID)));

и это

return _context.Communications.Where
(u => user.UserLocations.Any
(x => x.LID.Equals
(u.Intention.UID)));

и это

var thislist = from Intentions in _context.Intentions
                           join UserLocations in user.UserLocations
                           on Intentions.UID equals UserLocations.LID
                           select Intentions.UID;
            return _context.Communications.Where(u => u.Intention.Equals(thislist.Any()));

и это

var lidlist = user.UserLocations.Select(x => x.LID);
return _context.Communications.Where(x=> lidlist.Contains(x.Intention.UID)).ToList();

(это дает мне ошибку в выражении «Содержит», говоря: «Делегат System.Func<Communication,int,bool> не принимает 1 аргумент», не знаю, как исправить)

Наряду со всеми этими вариациями у меня также есть:

  • изменил мой метод, чтобы вернуть IQueryable<Communication>, а также попробовал List<Communication> при добавлении ToList() к моим запросам.

Ничего не работает. Независимо от того, что я пытаюсь, я всегда получаю это исключение

NotSupportedException не было обработано пользовательским кодом

Невозможно создать постоянное значение типа PreparisCore.BusinessEntities.UserLocation. В этом контексте поддерживаются только примитивные типы ("например, Int32, String и Guid").

Что я делаю неправильно??


person Matt Foxx Duncan    schedule 30.07.2012    source источник
comment
какие типы UID и LID?   -  person Darek    schedule 31.07.2012
comment
Хм, тогда вторая форма должна работать. Я бы использовал = для ясности. Я постараюсь написать тестовый пример, чтобы подтвердить.   -  person Darek    schedule 31.07.2012
comment
Какой делегат не принимает 1 аргумент? Обычно исключение точно указывает тип делегата. Какой тип возвращает ваш метод? Последний код должен работать, на мой взгляд. Остальные три действительно не могут работать.   -  person Slauma    schedule 31.07.2012
comment
Кажется, я обнаружил проблему со второй формой... BRB   -  person Darek    schedule 31.07.2012
comment
@Slauma System.FuncBusinesEntities.Communicaton,int,bool›   -  person Matt Foxx Duncan    schedule 31.07.2012
comment
Это время компиляции или ошибка/исключение во время выполнения?   -  person Slauma    schedule 31.07.2012
comment
Это исключение времени выполнения, все компилируется нормально   -  person Matt Foxx Duncan    schedule 31.07.2012
comment
Я имел в виду, что делегат xxx не принимает 1 ошибку аргумента (извините, я не понял этого). Это также исключение времени выполнения или ошибка компилятора? (Вы говорите ошибка в выражении «Содержит», что больше похоже на сообщение компилятора...) И, кстати: какую версию EF вы используете?   -  person Slauma    schedule 31.07.2012
comment
Ах, это ошибка компилятора. Основным исключением (в моем вопросе) является ошибка времени выполнения. Запуск .net 4   -  person Matt Foxx Duncan    schedule 31.07.2012
comment
Я могу воспроизвести ошибку компилятора, когда в Where(x=> lidlist.Contains(x.Intention.UID)) что-то написано неправильно, например: lidxyzlist или Contain или Intenton или AID или... Сообщение очень странное, потому что оно не говорит та или иная переменная/свойство не объявлены чего я и ожидал. Но если я исправлю все орфографические ошибки, он скомпилируется (и я верю, что тогда он будет работать правильно без исключения). Можешь еще раз проверить, все ли правильно написано?   -  person Slauma    schedule 31.07.2012
comment
Перепроверил, все верно. Однако @Darek обнаружил мою проблему в ответе ниже - мне нужно было добавить .ToList() к моим объектам Communication и Intention. Дох!   -  person Matt Foxx Duncan    schedule 31.07.2012
comment
Можете ли вы проверить ошибку компилятора в окне вывода компилятора, если есть более одной ошибки? Я получаю ваше сообщение об ошибке в окне всплывающей подсказки, когда я навожу курсор на строку с волнистой линией ошибки, но в окне вывода на самом деле более одной ошибки, которая может дать более четкое представление о том, что не так. (Я спрашивал здесь о проблеме: stackoverflow.com/questions/11738417/, особенно см. Edit в вопросе.)   -  person Slauma    schedule 31.07.2012
comment
Привет, сегодня утром я попытался скомпилировать и получил следующие ошибки: i.imgur.com/jaONi.png Прочитав ваш вопрос, я также добавлю, что я получаю закорючки под x => lidlist.Contains(x.Intention.UID))   -  person Matt Foxx Duncan    schedule 31.07.2012


Ответы (2)


Учитывая этот код:

namespace CollectionsWithIntentions
{
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;

    internal class Program
    {
        #region Methods

        private static void Main(string[] args)
        {
            var communications = new[]
                {
                    new Communication { Intention = new Intention { UID = 1 } },
                    new Communication { Intention = new Intention { UID = 2 } },
                    new Communication { Intention = new Intention { UID = 3 } },
                    new Communication { Intention = new Intention { UID = 4 } },
                };
            var users = new[]
                {
                    new User { UserLocations = new List<UserLocation>(new[] { new UserLocation { LID = 2 },new UserLocation{LID=5}  }) },
                    new User { UserLocations = new List<UserLocation>(new[] { new UserLocation { LID = 3 } }) }
                };

            IEnumerable<Communication> res =
                communications.Where(w => users.Any(a => a.UserLocations.Any(b=>b.LID == w.Intention.UID)));
            foreach (Communication communication in res)
            {
                Trace.WriteLine(communication);
            }
        }

        #endregion
    }

    internal class Communication
    {
        #region Public Properties

        public Intention Intention { get; set; }

        #endregion

        #region Public Methods and Operators

        public override string ToString()
        {
            return string.Concat("Communication-> Intention:", this.Intention.UID);
        }

        #endregion
    }

    internal class Intention
    {
        #region Public Properties

        public int UID { get; set; }

        #endregion
    }

    internal class User
    {
        #region Public Properties

        public List<UserLocation> UserLocations { get; set; }

        #endregion
    }

    internal class UserLocation
    {
        #region Public Properties

        public int LID { get; set; }

        #endregion
    }
}

Я получаю этот результат:

Communication-> Intention:2
Communication-> Intention:3

Я что-то упустил?

person Darek    schedule 30.07.2012
comment
Одно исправление, я ищу только одного пользователя, но ваш код выглядит почти так же, как мой второй пример. Еще одно отличие, которое следует отметить, заключается в том, что все эти объекты являются объектами EntityObjects(UserLocation, User, Communication, Intention) или EntityCollections(Userlocations). UserLocations — это объект-мост между двумя объектами User и Location. - person Matt Foxx Duncan; 31.07.2012
comment
Я могу подтвердить, что при использовании EF возникает та же ошибка... Изучение - person Darek; 31.07.2012
comment
Ответ доступен в этом опубликовать. Так что в вашем случае вам придется сначала добавить Communications и UserLocations в список. Как это работает: ctx.Communications.ToList().Where(w1 => user.Locations.ToList(). Any(a1 => a1.LID == w1.Intentions.UID)) .ToList(); - person Darek; 31.07.2012
comment
Вы фантастичны :) Это было оно! Я чувствую, что здесь уместно приложить руку к удару справа. Спасибо вам за помощь!! - person Matt Foxx Duncan; 31.07.2012
comment
@MattFoxxDuncan и Дарек: Решение в комментарии довольно злое, потому что оно сначала загрузит всю таблицу Communications в память, прежде чем фильтр вообще будет применен. Может проблема не в 100 записях в этой таблице, а в 100000 или в миллионе? - person Slauma; 31.07.2012
comment
@Slauma, да, действительно. Так что лучше профильтровать его заранее. В качестве альтернативы вы можете использовать этот путь, но он тоже не идеален. - person Darek; 31.07.2012
comment
@MattFoxxDuncan и Дарек: На самом деле последний запрос в вопросе должен работать. Я открыл вопрос, потому что не совсем понимаю ошибку компилятора, которую выдает этот запрос: where-extension-method" title="как работает разрешение перегрузки метода linq, где метод расширения"> stackoverflow.com/questions/11738417/ - person Slauma; 31.07.2012
comment
@Slauma спасибо за предупреждение о проблемах с производительностью позже. Я буду добавлять некоторые функции фильтрации. - person Matt Foxx Duncan; 31.07.2012

Из последних двух ошибок компилятора, которые вы указали в одном из своих комментариев...

введите здесь описание изображения

... Я бы пришел к выводу, что Intention.UID является обнуляемым типом int?, а не необнуляемым int, как вы сказали в комментариях. Это действительно не компилируется. Попробуйте изменить свой последний запрос на:

var lidlist = user.UserLocations.Select(x => x.LID);
return _context.Communications
    .Where(x => x.Intention.UID.HasValue
             && lidlist.Contains(x.Intention.UID.Value))
    .ToList();

Остальные три запроса не работают, потому что user.UserLocations — это коллекция непримитивного пользовательского типа в памяти (для генерируемого SQL-запроса это «постоянное» значение), а EF не поддерживает построение SQL-запроса с таким постоянный настраиваемый тип.

person Slauma    schedule 31.07.2012