Я работаю над ASP.NET Core 2.1 API и пытаюсь передать лямбда-выражение в виде строки в теле POST, которое затем оценивается в моем хранилище, чтобы вернуть набор записей.Я слежу за этим сообщением в блоге и использую CSharpScript.EvaluateAsync для анализа строки и создания лямбда-выражения в форме, которую я могу использовать в предложении WHERE запроса linq.
Отлично работает с отдельными элементами,Например, если я передам
"f => f.CompanyName.Contains(\"Dav\")"
, вернется нужный набор записей.
Однако, если я попытаюсь ...
"f => f.CompanyName.Contains(\"Dav\") || f.PrimaryContactTitle.Contains(\"Dav\")"
, я получу исключениеуказав ...
System.NullReferenceException: Arg_NullReferenceException
at Submission#0.<>c.<<Initialize>>b__0_0(Company f)
at System.Linq.Utilities.<>c__DisplayClass1_0`1.<CombinePredicates>b__0(TSource x)
at System.Linq.Enumerable.WhereEnumerableIterator`1.ToArray()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.OrderedEnumerable`1.GetEnumerator()+MoveNext()
at System.Linq.Enumerable.WhereEnumerableIterator`1.GetCount(Boolean onlyIfCheap)
at System.Linq.Enumerable.Count[TSource](IEnumerable`1 source)
at System.Linq.Queryable.Count[TSource](IQueryable`1 source)
, когда я пытаюсь работать с результирующей коллекцией IQueryable.
Есть ли какая-либо альтернатива использованию ||или && как операторы OR и AND в лямбда-выражении запроса linq, которое можно правильно проанализировать с помощью CSharpScript.EvaluateAsync?
Вот пример моего тела запроса;
{
"filter":""f => f.CompanyName.Contains(\"Dav\") || f.PrimaryContactTitle.Contains(\"Dav\")",
"pageNumber": 1,
"pageSize": 20,
"deleteFlag": false,
"orderBy": "CompanyName desc",
"Fields": null
}
Вот мойсоответствующий код репо ...
public async Task<PagedList<Company>> GetFilteredPagedList(CompaniesResourceParameters resourceParams)
{
try
{
var options = ScriptOptions.Default.AddReferences(typeof(Company).Assembly);
var companyFilterExpression = await CSharpScript.EvaluateAsync<Func<Company, bool>>(resourceParams.Filter, options);
//Get the records ordered by the OrderBy property of the passed in resourceParams
var collectionBeforePaging =
_manifestContext.Companies
.AsNoTracking()
.Include(c => c.Sites)
.Where(companyFilterExpression).AsQueryable()
.Where(d => d.DeleteFlag == false)
.ApplySort(resourceParams.OrderBy, _propertyMappingService.GetPropertyMapping<CompanyDto, Company>());
return PagedList<Company>.Create(collectionBeforePaging,
resourceParams.PageNumber,
resourceParams.PageSize); // <-- This is where the Exception is thrown as it tries to work with the collectionBeforePaging
}
catch (Exception ex)
{
_logger.LogError(ex, $"Exception trying to retrieve a paged list of records using the filter {resourceParams}");
throw;
}
}
Исключение возникает, когда я нажимаю на строку ...
return PagedList<Company>.Create(collectionBeforePaging,
resourceParams.PageNumber,
resourceParams.PageSize)
Вот метод Create, который вызывается при возникновении исключения.
public static PagedList<T> Create(IQueryable<T> source, int pageNumber, int pageSize)
{
var count = source.Count();
var items = source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList();
return new PagedList<T>(items, count, pageNumber, pageSize);
}
Исключение возникает, когда я пытаюсь использовать IENumerable в строке
var count = source.Count();
Это исключение не возникает, когда я использую фильтр, который не имеет ИЛИ или И,такие как ..
filter":"f => f.CompanyName.Contains(\"Dav\")"
или
filter":"f => f.PrimaryContactName.Contains(\"Dav\")"
Итак, я считаю, что проблема с использованием ||operator.
* ОБНОВЛЕНИЕ 1 *
Как указывал NineBerry, я не выполнял нулевую проверку перед выполнением * .Contains () в моей лямбде.Вот мой полный пересмотренный фильтр, который я передаю в запрос HttpClient API в моем клиенте.
var filter = $"f => f.CompanyName.Contains(\"{searchValue}\") || " +
$"(f.PrimaryContactName != null && f.PrimaryContactName.Contains(\"{searchValue}\")) || " +
$"(f.PrimaryContactTitle != null && f.PrimaryContactTitle.Contains(\"{searchValue}\")) || " +
$"(f.PrimaryContactTitle != null && f.PrimaryContactTitle.Contains(\"{searchValue}\")) || " +
$"(f.PrimaryContactEmail != null && f.PrimaryContactEmail.Contains(\"{searchValue}\"))";
И теперь мой поисковый фильтр работает как положено.
Это также подтверждает, что я могу использовать ||и && в моей лямбда-строке, которая анализируется CSharpScript.ExecuteAsync () без какой-либо специальной обработки.