При использовании CSharpScript.EvaluateAsync, как я могу использовать II или && в своем лямбда-выражении - PullRequest
0 голосов
/ 12 октября 2018

Я работаю над 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 () без какой-либо специальной обработки.

...