Подвыражение LINQ не принимает значения переменных

#c# #entity-framework

Вопрос:

У меня есть 3 контекста для 3 разных серверов. Основные данные приложения используют контекст1, подключающийся к SQL1. В службе веб-API я получаю записи людей асинхронно из context2, подключающегося к SQL2. Он возвращает 4800 записей. Записи дополнительно фильтруются по тому userFacility , что является результатом хранимой процедуры из контекста3, подключающейся к SQL3.

Все подходы работают на моей машине разработки с Visual Studio 2019 и IIS Express. При публикации на сервере IIS в нашей сети работает только Подход 2. Похоже, EF нравится только постоянное значение во внутреннем выражении, но не переменное значение. Кто-нибудь знает, в чем может быть проблема?

 IEnumerable<PeopleDTO> people= await aHelper.GetPeopleAsync(aRepository, defaultQuarter, criteria);
/* sample Facility property of People values are
(1V01) (402) Togus, ME
(1V01) (518) Bedford, MA
(1V01) (523) Boston, MA
(1V01) (608) Manchester, NH
(1V01) (631) Central Western Massachusetts
(3V12) (587) Eastern Colorado, CO
*/

List<string> userFacilities = new List<string>(){“608”,”518”,”674”, "587","648"};

/* approach 1 works in VS but not in IIS */
       pepole= pepole.Where(x => userFacilities.Any(y=> x.Facility.Contains(y)));

/* approach 2 works in both in VS and IIS */
       pepole= pepole.Where(x => userFacilities.Any(y=> x.Facility.Contains("587")));


/* Approach 3 works in VS but not in IIS */
List<PeopleDTO> viewablePeople = new List<PeopleDTO>();

foreach (PeopleDTO p in people)
{
    foreach (string y in userFacilities)
    {
        /* doesn't work in IIS but works in VS IIS  Express if y is a constant*/
        if (p.Facility.IndexOf(y) >= 0)
        {
            viewablePeople.Add(p); 
            break;
        }
    }
}

return Ok(viewablePeople);
 
       public partial class PeopleDTO
      {
        [DisplayName("Facility")]
        public string Facility { get; set; } 

        [DisplayName("District")]
        public string District { get; set; }

        [DisplayName("Name")]
        public string Name { get; set; }

        [DisplayName("SSN")]
        public string PTFSSN { get; set; }

        [DisplayName("FSOD SSN")]
        public string FSODSSN { get; set; }

        [DisplayName("Fiscal Period")]
        public string FiscalPeriod { get; set; }

        [DisplayName("Numeric Fiscal Period")]
        public int FiscalPeriodInt { get; set; }

        [DisplayName("Episode")]
        public IEnumerable<EpisodeDTO> Episodes { get; set; }

        public PeopleDTO() {
          Episodes = new List<EpisodeDTO>();
        }
 

Комментарии:

1. Есть ли какая-либо причина, по которой константа, которую вы используете: "587" для предоставления рабочих примеров в IIS, не включена в userFacilities список ( “608”,”518”,”674” )?

2. Вы запрашиваете одну и ту же базу данных на одном сервере из всех систем или существуют отдельные базы данных на отдельных серверах? Если отдельные, то как они были созданы: с помощью миграции или другими способами? Также, если отдельно: являются ли данные в них точно на 100% полностью одинаковыми? Также, если отдельно: одинаковы ли их COLLATION настройки?

3. @Питер Б: Хороший вопрос. Возможность использования извлекается из другой базы данных с другого сервера путем выполнения хранимой процедуры с помощью EF FromSqlRaw() или ExecuteSqlRawAsync(). Затем каждый из уникальных объектов возвращаемых записей добавляется в локальную переменную userFacility в виде типа List<string>. Класс контекста создается с помощью основных инструментов EF Power Tools. Пожалуйста, обратитесь к моему сообщению о структуре людей. Я просто сравниваю каждую строку в списке возможностей пользователя с людьми. Объект, который имеет более длинные строковые значения.

4. Что на самом деле означает «не работает»? Ошибки, никаких результатов? И что это за бренд базы данных?

Ответ №1:

Я думаю, что переименование переменной fac может решить проблему, если предположить, что это глобальная переменная, потому что я не вижу ее в коде, интерполяция в первом подходе, похоже, ни на что не ссылается

Комментарии:

1. @Medina, fac-это следующее имя переменной . Любой(fac=>….) и в каждом(строка fac ….)

2. Да, но входной параметр должен называться одинаково для выражения, если вы не получаете доступ к чему-то внутри, попробуйте это, просто чтобы посмотреть, работает ли это string facility = «xxx»; pepole= pepole. Где(x => Возможности пользователя. Любой(fac => x.Объект. Содержит(объект)));

3. @Medina: да, я использую fac во внутреннем выражении для ссылки на значение (объект) в функциях пользователя и сравниваю его с переменной внешнего выражения x (люди), чтобы увидеть, содержит ли x fac. Также ваше выражение работает, когда facility = «xxx» в качестве константы вместо List<string>.

Ответ №2:

EF вообще не имеет никакого отношения к вашим данным, так как у вас всего 2 списка в памяти компьютера, и вы больше не используете контекст БД. Поэтому вам не нужно использовать персонал типа «EF.Функции.Например», который был создан для преобразования linq в t-sql и очень неэффективен, когда он используется для чего-то другого.

Я создал специальную функцию GetIt, которая выполняет проверку, и я уверен, что она будет работать везде, так как она использует только систему c#.Коллекции.Общее пространство имен. Я думаю, что почти каждое приложение на c# использует это пространство имен, и я никогда не слышал ни о каких проблемах с ним.

Вы проверяли список людей перед началом каждого теста? Я думаю, что ваша проблема с кодом заключается в тестировании. Поскольку вы используете конструкцию people=people…, список мутирует после каждого тестирования. И в следующем приложении используются другие данные, чем в предыдущем.

Или аХелпер.GetPeopleAsync… также может приводить различные данные при использовании VS и после развертывания в IIS.

Я не вижу смысла использовать первые 4 подхода, так как это не EF. Поэтому имеет смысл только еще раз протестировать подход № 5, исключая предыдущие подходы.

Это демо-версия, которая была протестирована в VS. Вы можете попробовать это в IIS. Если он там работает, то проблема в другом.Функция GetPeopleAsync

 void Main()
{

 people = people.Where(x => GetIt(x.Facility)).ToList();

bool GetIt(string f)
{
    foreach (var uf in userFacilities)
    {
        if ( f.IndexOf(uf) >= 0 ) return true;
    }
    return false;
}


var people  = new List<People> {
new People{ Name="name",Facility="(1V01) (402) Togus, ME"},
new People{ Name="name",Facility="(1V01)(518) Bedford, MA"},
new People{ Name="name",Facility="(1V01)(523) Boston, MA"},
new People{ Name="name",Facility="(1V01)(608) Manchester, NH"},
new People{ Name="name",Facility="(1V01)(631) Central Western Massachusetts"},
new People{ Name="name",Facility="(3V12)(587) Eastern Colorado, CO"}
};

List<string> userFacilities = new List<string>() {"608","518","674", "587","648"};

}

public partial class People
{
    public string Facility { get; set; }
    public string Name { get; set; }
}
 

Комментарии:

1. Люди. Объект имеет строку «abc def 587 efg» или «xyz123 daeada» или «674abcde adakhlkl».

2. @Serge: вы говорите: «поскольку обе коллекции уже находятся в памяти…», но все, что мы видим, — это IEnumerable, который с таким же успехом может быть живым объектом запроса, если я не ошибаюсь. Вопрос не раскрывает никаких деталей реализации GetPeopleAsync .

3. @PeterB » В сервисе WebAPI я получаю записи о людях асинхронно. Он ВОЗВРАЩАЕТ 4800 записей. Затем я ДОПОЛНИТЕЛЬНО фильтрую результат по удобству пользователя …» . Плюс сертификат подхода 5 явно не будет работать против БД. Но ИМХО лучше дождаться ПО, чем начинать спекуляции.

4. @Searge: Да, народ можно перечислить. Удобство использования-это список<строка>. Таким образом, они оба работают в памяти клиента (IIS). Кроме того, подход 5 является базовым таким же, как и ваша функция GetIt ().