Dynamic Linq error with filter expression #1909

Closed
opened 2026-01-29 18:00:06 +00:00 by claunia · 8 comments
Owner

Originally created by @rpgkaiser on GitHub (Nov 19, 2025).

Bug Description
The generated filter expression (in Dynamic Linq format), when using columns with nullable data types, is producing an error when the filter expression is used as a predicate in the Where Linq method of the official System.Linq.Dynamic.Core library.

Example of filter expression with error:
x => ((((x == null) ? null : x.FinanceStartDate) ?? null) == DateTime.SpecifyKind(DateTime.Parse("2025-08-01", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind), DateTimeKind.Unspecified))

Error message for the given filter expression:
Operator '==' incompatible with operand types 'Object' and 'DateTime'

If the data type of the property is changed to the not nullable variant (like DateTime instead of DateTime?) the error disappears.

To work around this, I had included an explicit conversion in the left part of the comparison. The fixed expression looks like this:
`x => (DateTime?(((x == null) ? null : x.FinanceStartDate) ?? null) == DateTime.SpecifyKind(DateTime.Parse("2025-08-01",

To Reproduce
Steps to reproduce the behavior:

  1. Add a RadzenDataGrid with a data model with some nullable properties (like DateTime?).
  2. Open the page and apply some filter for the column associated with the nullable data type.
  3. See the error in the server console or browser dev-tools.

Screenshots

Image

Expected behavior

  • It would be great if the generated filter expression include the explicit conversion if the filter type is nullable.
  • It would be great if the column could define how to create the filter expression (using the current implementation by default), instead of the fixed/centralized way used now in the QueryableExtension.ToFilterString method. This will improve the extensibility level.

Desktop (please complete the following information):

  • OS: Windows 11
  • Browser: Chrome
  • Version: 142.0.7444.163

Additional context
Add any other context about the problem here.

Originally created by @rpgkaiser on GitHub (Nov 19, 2025). **Bug Description** The generated filter expression (in Dynamic Linq format), when using columns with nullable data types, is producing an error when the filter expression is used as a predicate in the `Where` Linq method of the official **_System.Linq.Dynamic.Core_** library. Example of filter expression with error: `x => ((((x == null) ? null : x.FinanceStartDate) ?? null) == DateTime.SpecifyKind(DateTime.Parse("2025-08-01", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind), DateTimeKind.Unspecified))` Error message for the given filter expression: _Operator '==' incompatible with operand types 'Object' and 'DateTime'_ If the data type of the property is changed to the not nullable variant (like `DateTime` instead of `DateTime?`) the error disappears. To work around this, I had included an [explicit conversion](https://dynamic-linq.net/expression-language#explicit-conversion) in the left part of the comparison. The fixed expression looks like this: `x => (DateTime?(((x == null) ? null : x.FinanceStartDate) ?? null) == DateTime.SpecifyKind(DateTime.Parse("2025-08-01", **To Reproduce** Steps to reproduce the behavior: 1. Add a `RadzenDataGrid` with a data model with some nullable properties (like `DateTime?`). 2. Open the page and apply some filter for the column associated with the nullable data type. 4. See the error in the server console or browser dev-tools. **Screenshots** <img width="1103" height="981" alt="Image" src="https://github.com/user-attachments/assets/3f5df94c-6d85-456f-99dc-9f801fda8a18" /> **Expected behavior** - It would be great if the generated filter expression include the explicit conversion if the filter type is nullable. - It would be great if the column could define how to create the filter expression (using the current implementation by default), instead of the fixed/centralized way used now in the `QueryableExtension.ToFilterString` method. This will improve the extensibility level. **Desktop (please complete the following information):** - OS: Windows 11 - Browser: Chrome - Version: 142.0.7444.163 **Additional context** Add any other context about the problem here.
Author
Owner

@enchev commented on GitHub (Nov 20, 2025):

Almost all of our demos are using nullable DateTime - for example this one:
https://blazor.radzen.com/datagrid
Can you let us know how to replicate this error?

@enchev commented on GitHub (Nov 20, 2025): Almost all of our demos are using nullable DateTime - for example this one: https://blazor.radzen.com/datagrid Can you let us know how to replicate this error?
Author
Owner

@rpgkaiser commented on GitHub (Nov 20, 2025):

Yes, I saw it, but in your demos the Where Linq method is called almost all the times passing the collection of columns or filter descriptors as parameters instead of using the Dynamic Linq serialization of the filters.
The only place in the demos using the Dynamic Linq serialization of the filters is in the PivotDataGridLoadData.razor, but that is an extension method of the Radzen library, not the method from the System.Linq.Dynamic.Core library.
The issue I'm reporting is related with the Dynamic Linq serialization of the filters, when using nullable value-type properties (like DateTime? or Decimal?) used with the System.Linq.Dynamic.Core library.

I'll try to create a small demo project to show you.

@rpgkaiser commented on GitHub (Nov 20, 2025): Yes, I saw it, but in your demos the `Where` _Linq_ method is called almost all the times passing the collection of columns or filter descriptors as parameters instead of using the _Dynamic Linq_ serialization of the filters. The only place in the demos using the _Dynamic Linq_ serialization of the filters is in the `PivotDataGridLoadData.razor`, but that is an extension method of the **_Radzen_** library, not the method from the `System.Linq.Dynamic.Core` library. The issue I'm reporting is related with the _Dynamic Linq_ serialization of the filters, when using nullable value-type properties (like `DateTime?` or `Decimal?`) used with the `System.Linq.Dynamic.Core` library. I'll try to create a small demo project to show you.
Author
Owner

@enchev commented on GitHub (Nov 21, 2025):

Here is adopted version of this demo for refernce: https://blazor.radzen.com/datagrid-loaddata?theme=material3

@using RadzenBlazorDemos.Data
@using RadzenBlazorDemos.Models.Northwind
@using System.Linq.Dynamic.Core
@inherits DbContextPage

<RadzenButton Text="Reset" Click="@Reset" Style="margin-bottom: 20px;" />
<RadzenDataGrid style="height: 335px" @ref="grid" IsLoading=@isLoading Count="@count" Data="@employees" LoadData="@LoadData" AllowSorting="true" AllowFiltering="true" AllowPaging="true" PageSize="4" PagerHorizontalAlign="HorizontalAlign.Center" ColumnWidth="200px">
    <Columns>
        <RadzenDataGridColumn Property="@nameof(Employee.EmployeeID)" Filterable="false" Title="ID" Frozen="true" Width="80px" TextAlign="TextAlign.Center" />
        <RadzenDataGridColumn Title="Photo" Frozen="true" Sortable="false" Filterable="false" Width="80px" TextAlign="TextAlign.Center" >
            <Template Context="data">
                <RadzenImage Path="@data.Photo" class="rz-gravatar" AlternateText="@(data.FirstName + " " + data.LastName)" />
            </Template>
        </RadzenDataGridColumn>
        <RadzenDataGridColumn Property="@nameof(Employee.FirstName)" Title="First Name" Frozen="true" Width="160px"/>
        <RadzenDataGridColumn Property="@nameof(Employee.LastName)" Title="Last Name" Width="160px"/>
        <RadzenDataGridColumn Property="@nameof(Employee.Title)" Title="Job Title" 
            Type="typeof(IEnumerable<string>)" FilterValue="@selectedTitles" FilterOperator="FilterOperator.Contains" Width="200px">
            <FilterTemplate>
                <RadzenDropDown @bind-Value=@selectedTitles Style="width:100%" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", "select title" }})"
                    Change=@OnSelectedTitlesChange Data="@(titles)" AllowClear="true" Multiple="true" />
            </FilterTemplate>
        </RadzenDataGridColumn>
        <RadzenDataGridColumn Property="@nameof(Employee.TitleOfCourtesy)" Title="Title" Width="120px" />
        <RadzenDataGridColumn Property="@nameof(Employee.BirthDate)" Title="Birth Date" FormatString="{0:d}" Width="160px" />
        <RadzenDataGridColumn Property="@nameof(Employee.HireDate)" Title="Hire Date" FormatString="{0:d}" Width="160px" />
        <RadzenDataGridColumn Property="@nameof(Employee.Address)" Title="Address" Width="200px" />
        <RadzenDataGridColumn Property="@nameof(Employee.City)" Title="City" Width="160px" />
        <RadzenDataGridColumn Property="@nameof(Employee.Region)" Title="Region" Width="160px" />
        <RadzenDataGridColumn Property="@nameof(Employee.PostalCode)" Title="Postal Code" Width="160px" />
        <RadzenDataGridColumn Property="@nameof(Employee.Country)" Title="Country" Width="160px" />
        <RadzenDataGridColumn Property="@nameof(Employee.HomePhone)" Title="Home Phone" Width="160px" />
        <RadzenDataGridColumn Property="@nameof(Employee.Extension)" Title="Extension" Width="160px" />
        <RadzenDataGridColumn Property="@nameof(Employee.Notes)" Title="Notes" Width="300px" />
    </Columns>
</RadzenDataGrid>

<RadzenCard class="rz-mt-6">
    <RadzenText TextStyle="TextStyle.H6" TagName="TagName.H2" class="rz-mb-4">Perform custom data-binding</RadzenText>
    <RadzenText TextStyle="TextStyle.Body1">
        1. Set the Data and Count properties.
    </RadzenText>
        <pre class="rz-mt-4 rz-p-4">
            <code>&lt;RadzenDataGrid Count="@@count" Data="@@employees"</code>
        </pre>
    <RadzenText TextStyle="TextStyle.Body1">
        2. Handle the LoadData event and update the Data and Count backing fields (<code>employees</code> and <code>count</code> in this case).
    </RadzenText>
        <pre class="rz-mt-4 rz-p-4">
            <code>
void LoadData(LoadDataArgs args)
{
    var query = dbContext.Employees.AsQueryable();

    if (!string.IsNullOrEmpty(args.Filter))
    {
        query = query.Where(grid.ColumnsCollection);
    }

    if (!string.IsNullOrEmpty(args.OrderBy))
    {
        query = query.OrderBy(args.OrderBy);
    }

    count = query.Count();

    employees = query.Skip(args.Skip.Value).Take(args.Top.Value).ToList();


} 
            </code>
        </pre>
</RadzenCard>
@code {
    RadzenDataGrid<Employee> grid;
    int count;
    IEnumerable<Employee> employees;
    bool isLoading = false;

    List<string> titles = new List<string> {"Sales Representative", "Vice President, Sales", "Sales Manager", "Inside Sales Coordinator" };
    IEnumerable<string> selectedTitles;

    async Task OnSelectedTitlesChange(object value)
    {
        if (selectedTitles != null && !selectedTitles.Any())
        {
            selectedTitles = null;  
        }
        
        await grid.FirstPage();
    }

    async Task Reset()
    {
        grid.Reset(true); 
        await grid.FirstPage(true);
    }

    async Task LoadData(LoadDataArgs args)
    {
        isLoading = true;

        await Task.Yield();

        var query = dbContext.Employees.AsQueryable();

        if (!string.IsNullOrEmpty(args.Filter))
        {
            // Query cannot be transalated to SQL and filtering will be performed in-memory.
            if (selectedTitles?.Any() == true)
            {
                query = query.ToList().AsQueryable();
            }
            // Filter via the Where method
            query = query.Where(grid.ColumnsCollection.ToFilterString());
        }

        if (!string.IsNullOrEmpty(args.OrderBy))
        {
            // Sort via the OrderBy method
            query = query.OrderBy(args.OrderBy);
        }

        // Important!!! Make sure the Count property of RadzenDataGrid is set.
        count = query.Count();

        // Perform paging via Skip and Take.
        employees = query.Skip(args.Skip.Value).Take(args.Top.Value).ToList();

        isLoading = false;
    }
}

Image
@enchev commented on GitHub (Nov 21, 2025): Here is adopted version of this demo for refernce: https://blazor.radzen.com/datagrid-loaddata?theme=material3 ``` @using RadzenBlazorDemos.Data @using RadzenBlazorDemos.Models.Northwind @using System.Linq.Dynamic.Core @inherits DbContextPage <RadzenButton Text="Reset" Click="@Reset" Style="margin-bottom: 20px;" /> <RadzenDataGrid style="height: 335px" @ref="grid" IsLoading=@isLoading Count="@count" Data="@employees" LoadData="@LoadData" AllowSorting="true" AllowFiltering="true" AllowPaging="true" PageSize="4" PagerHorizontalAlign="HorizontalAlign.Center" ColumnWidth="200px"> <Columns> <RadzenDataGridColumn Property="@nameof(Employee.EmployeeID)" Filterable="false" Title="ID" Frozen="true" Width="80px" TextAlign="TextAlign.Center" /> <RadzenDataGridColumn Title="Photo" Frozen="true" Sortable="false" Filterable="false" Width="80px" TextAlign="TextAlign.Center" > <Template Context="data"> <RadzenImage Path="@data.Photo" class="rz-gravatar" AlternateText="@(data.FirstName + " " + data.LastName)" /> </Template> </RadzenDataGridColumn> <RadzenDataGridColumn Property="@nameof(Employee.FirstName)" Title="First Name" Frozen="true" Width="160px"/> <RadzenDataGridColumn Property="@nameof(Employee.LastName)" Title="Last Name" Width="160px"/> <RadzenDataGridColumn Property="@nameof(Employee.Title)" Title="Job Title" Type="typeof(IEnumerable<string>)" FilterValue="@selectedTitles" FilterOperator="FilterOperator.Contains" Width="200px"> <FilterTemplate> <RadzenDropDown @bind-Value=@selectedTitles Style="width:100%" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", "select title" }})" Change=@OnSelectedTitlesChange Data="@(titles)" AllowClear="true" Multiple="true" /> </FilterTemplate> </RadzenDataGridColumn> <RadzenDataGridColumn Property="@nameof(Employee.TitleOfCourtesy)" Title="Title" Width="120px" /> <RadzenDataGridColumn Property="@nameof(Employee.BirthDate)" Title="Birth Date" FormatString="{0:d}" Width="160px" /> <RadzenDataGridColumn Property="@nameof(Employee.HireDate)" Title="Hire Date" FormatString="{0:d}" Width="160px" /> <RadzenDataGridColumn Property="@nameof(Employee.Address)" Title="Address" Width="200px" /> <RadzenDataGridColumn Property="@nameof(Employee.City)" Title="City" Width="160px" /> <RadzenDataGridColumn Property="@nameof(Employee.Region)" Title="Region" Width="160px" /> <RadzenDataGridColumn Property="@nameof(Employee.PostalCode)" Title="Postal Code" Width="160px" /> <RadzenDataGridColumn Property="@nameof(Employee.Country)" Title="Country" Width="160px" /> <RadzenDataGridColumn Property="@nameof(Employee.HomePhone)" Title="Home Phone" Width="160px" /> <RadzenDataGridColumn Property="@nameof(Employee.Extension)" Title="Extension" Width="160px" /> <RadzenDataGridColumn Property="@nameof(Employee.Notes)" Title="Notes" Width="300px" /> </Columns> </RadzenDataGrid> <RadzenCard class="rz-mt-6"> <RadzenText TextStyle="TextStyle.H6" TagName="TagName.H2" class="rz-mb-4">Perform custom data-binding</RadzenText> <RadzenText TextStyle="TextStyle.Body1"> 1. Set the Data and Count properties. </RadzenText> <pre class="rz-mt-4 rz-p-4"> <code>&lt;RadzenDataGrid Count="@@count" Data="@@employees"</code> </pre> <RadzenText TextStyle="TextStyle.Body1"> 2. Handle the LoadData event and update the Data and Count backing fields (<code>employees</code> and <code>count</code> in this case). </RadzenText> <pre class="rz-mt-4 rz-p-4"> <code> void LoadData(LoadDataArgs args) { var query = dbContext.Employees.AsQueryable(); if (!string.IsNullOrEmpty(args.Filter)) { query = query.Where(grid.ColumnsCollection); } if (!string.IsNullOrEmpty(args.OrderBy)) { query = query.OrderBy(args.OrderBy); } count = query.Count(); employees = query.Skip(args.Skip.Value).Take(args.Top.Value).ToList(); } </code> </pre> </RadzenCard> @code { RadzenDataGrid<Employee> grid; int count; IEnumerable<Employee> employees; bool isLoading = false; List<string> titles = new List<string> {"Sales Representative", "Vice President, Sales", "Sales Manager", "Inside Sales Coordinator" }; IEnumerable<string> selectedTitles; async Task OnSelectedTitlesChange(object value) { if (selectedTitles != null && !selectedTitles.Any()) { selectedTitles = null; } await grid.FirstPage(); } async Task Reset() { grid.Reset(true); await grid.FirstPage(true); } async Task LoadData(LoadDataArgs args) { isLoading = true; await Task.Yield(); var query = dbContext.Employees.AsQueryable(); if (!string.IsNullOrEmpty(args.Filter)) { // Query cannot be transalated to SQL and filtering will be performed in-memory. if (selectedTitles?.Any() == true) { query = query.ToList().AsQueryable(); } // Filter via the Where method query = query.Where(grid.ColumnsCollection.ToFilterString()); } if (!string.IsNullOrEmpty(args.OrderBy)) { // Sort via the OrderBy method query = query.OrderBy(args.OrderBy); } // Important!!! Make sure the Count property of RadzenDataGrid is set. count = query.Count(); // Perform paging via Skip and Take. employees = query.Skip(args.Skip.Value).Take(args.Top.Value).ToList(); isLoading = false; } } ``` <img width="1920" height="1080" alt="Image" src="https://github.com/user-attachments/assets/de9c25c3-a197-454a-88b0-297bed619b4e" />
Author
Owner

@rpgkaiser commented on GitHub (Nov 21, 2025):

Did you try to use the serialized filter expression with the official System.Linq.Dynamic.Core library? If you install this package and use one of the Where extension methods from this library, you will see the error I'm reporting.

@rpgkaiser commented on GitHub (Nov 21, 2025): Did you try to use the serialized filter expression with the official **_System.Linq.Dynamic.Core_** library? If you install this package and use one of the `Where` extension methods from this library, you will see the error I'm reporting.
Author
Owner

@enchev commented on GitHub (Nov 21, 2025):

We have abandoned this library year ago due to vulnerability issues. Check the demo I’ve posted which is using our own parser.

@enchev commented on GitHub (Nov 21, 2025): We have abandoned this library year ago due to vulnerability issues. Check the demo I’ve posted which is using our own parser.
Author
Owner

@rpgkaiser commented on GitHub (Nov 21, 2025):

I can't use your parser because I'm running the filters in a WebApi without Radzen, so I need to use the Dynamic Linq expression serialized by Radzen in my WebApi with the official System.Linq.Dynamic.Core library.
I suppose the serialized filter in Dynamic Linq format is intended to be used not only inside the Radzen library, right? And if it is using the Dynamic Linq format, should be OK to use it with the official Dynamic Linq library.
By the way, the security issues you mention were addressed since version 1.6.0. I'm not asking to change the Radzen.Blazor library to use it again, just to align the serialized filter expression with the format expected by the official library, that's all.

@rpgkaiser commented on GitHub (Nov 21, 2025): I can't use your parser because I'm running the filters in a WebApi without _Radzen_, so I need to use the _Dynamic Linq_ expression serialized by _Radzen_ in my WebApi with the official _System.Linq.Dynamic.Core_ library. I suppose the serialized filter in _Dynamic Linq_ format is intended to be used not only inside the _Radzen_ library, right? And if it is using the _Dynamic Linq_ format, should be OK to use it with the official _Dynamic Linq_ library. By the way, the security issues you mention were addressed since version 1.6.0. I'm not asking to change the Radzen.Blazor library to use it again, just to align the serialized filter expression with the format expected by the official library, that's all.
Author
Owner

@akorchev commented on GitHub (Nov 21, 2025):

Hi @rpgkaiser,

The expressions serialized by Radzen.Blazor are not compatible with the DynamicLinq library nor do we plan to maintain such compatibility. You have the following options to consume the serialized expression server-side:

  1. Use the Radzen.Blazor library server-side as well and parse. Then you can use it with regular Linq.
  2. Use Roslyn to parse the expression since it is valid C#.

Alternatively you can serialize the filters with your own code.

@akorchev commented on GitHub (Nov 21, 2025): Hi @rpgkaiser, The expressions serialized by Radzen.Blazor are not compatible with the DynamicLinq library nor do we plan to maintain such compatibility. You have the following options to consume the serialized expression server-side: 1. Use the Radzen.Blazor library server-side as well and [parse](https://github.com/radzenhq/radzen-blazor/blob/master/Radzen.Blazor/ExpressionParser.cs#L21). Then you can use it with regular Linq. 2. Use Roslyn to parse the expression since it is valid C#. Alternatively you can serialize the filters with your own code.
Author
Owner

@rpgkaiser commented on GitHub (Nov 21, 2025):

Ok, thanks for your help.

@rpgkaiser commented on GitHub (Nov 21, 2025): Ok, thanks for your help.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/radzen-blazor#1909