Hello,
I'm implementing a fully dynamic grid system on my project, with UrlAdaptor.
Actually I encountered a problem with backEnd filtering IQueryable DataSource with complex Object data field on grid columns.
(PS. The filtering works well with NON complex object/NON navigations columns.)
Ex. Error
(Complex Object / Navigation)
<e-grid-column field="Task.Title" type="string" headerText="TASK" width="" textAlign="Left"></e-grid-column>
From Method:
public IQueryable<T> PerformFilteringSyncfusion<T> (IQueryable<T> dataSource, DataManagerRequest dm) where T : class
{
DataOperations operation = new DataOperations();
if (dm.Where != null && dm.Where.Count > 0) //Filter
dataSource = operation.PerformFiltering(dataSource, dm.Where, dm.Where[0].Operator);
return dataSource;
}
Generates this error:
The LINQ expression 'DbSet<Report>()
.Where(r => r.IsDeleted == False && r.DateStart.Month == DateTime.Now.Month)
.OrderBy(r => r.DateStart)
.Join(
inner: DbSet<Task>(),
outerKeySelector: r => EF.Property<Guid?>(r, "IdTask"),
innerKeySelector: t => EF.Property<Guid?>(t, "Id"),
resultSelector: (o, i) => new TransparentIdentifier<Report, Task>(
Outer = o,
Inner = i
))
.Where(r => r.Inner == null ? null : new TaskDTO{
Title = r.Inner.Title,
Description = r.Inner.Description,
IsDefault = r.Inner.IsDefault,
IsDisabled = r.Inner.IsDisabled,
Reports = null,
ProductionOrderTasks = null,
Id = r.Inner.Id,
DateCreated = (DateTime?)r.Inner.DateCreated,
DateUpdated = r.Inner.DateUpdated,
IsDeleted = r.Inner.IsDeleted
}
!= null && (r.Inner.Title ?? "").ToLower().StartsWith("a"))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
Can you help me resolve this issue?
Thanks in advice, best regards.
Hi Martino,
Greetings from Syncfusion support.
Before proceeding with your solution, we would like you to share the below details.
Regards,
Joseph I.
Hello Joseph,
Thanks for the response, below the requested details:
<div class="col-12">
<ejs-grid id="grid-user" allowPaging="true" allowSorting="true" allowFiltering="true" allowResizing="true" allowExcelExport="true" enableAltRow="true" locale="it-IT" allowReordering="false" query="new ej.data.Query().expand('Task')">
<e-data-manager url="/Reports/Load" adaptor="UrlAdaptor"></e-data-manager>
<e-grid-pagesettings pageSize="12"></e-grid-pagesettings>
<e-grid-filterSettings type="Menu" mode="OnEnter"></e-grid-filterSettings>
<e-grid-columns>
<e-grid-column field="Id" headerText="ID" textAlign="Left" visible="false"></e-grid-column>
@* <e-grid-column field="ProductionOrder.Code" type="string" headerText="COMMESSA" width="" textAlign="Left"></e-grid-column> *@
<e-grid-column field="Task.Title" type="string" headerText="TASK" width="" textAlign="Left"></e-grid-column>
<e-grid-column field="HoursAmount" headerText="Ore" width="" textAlign="Left"></e-grid-column>
<e-grid-column field="DateStart" headerText="DATA" width="" textAlign="Left" customFormat="@(new { type ="date", format="dd/MM/yyyy" })"></e-grid-column>
@* <e-grid-column field="Description" headerText="DESCRIZIONE" width="" textAlign="Left"></e-grid-column> *@
<e-grid-column headerText="" width="40" textAlign="Center" template="#templateBtns"></e-grid-column>
</e-grid-columns>
</ejs-grid>
</div>
@* BTNS *@
<script id="templateBtns" type="text/x-template">
<button class="utility-button grid me-1" onclick="editReport(`${id}`)">
<i class="fa-solid fa-pencil"></i>
</button>
<button class="utility-button grid" onclick="deleteReport(`${id}`)">
<i class="fa-regular fa-trash-can"></i>
</button>
</script>
public class ReportDTO : BaseDTO {
public double HoursAmount { get; set; }
public DateTime DateStart { get; set; }
public DateTime DateEnd { get; set; }
public string? Description { get; set; }
#region Navigations
public Guid IdUser { get; set; }
public UserDTO User { get; set; }
public Guid IdProductionOrder { get; set; }
public ProductionOrderDTO ProductionOrder { get; set; }
public Guid IdTask { get; set; }
public TaskDTO Task { get; set; }
#endregion
}
public class BaseDTO {
public Guid Id { get; set; }
public string? UserCreate { get; set; }
public DateTime? DateCreated { get; set; }
public string? UserUpdate { get; set; }
public DateTime? DateUpdated { get; set; }
public bool IsDeleted { get; set; } = false;
}
// The tested navigation prop.
public class TaskDTO : BaseDTO {
public string Title { get; set; }
public string? Description { get; set; }
public bool IsDefault { get; set; } = false;
public bool IsDisabled { get; set; } = false;
#region Navigations
public List<ReportDTO> Reports { get; set; } = new List<ReportDTO>();
public List<ProductionOrderTaskDTO> ProductionOrderTasks { get; set; } = [];
#endregion
}
View: {grid} // reported up in this reply
Controller/Action (used to load, filter, sort etc.):
public async Task<IActionResult> Load([FromBody] DataManagerRequest dm){
try
{
IQueryable<ReportDTO> reports = await _reportService.GetAllQueryable(
filter: x => x.IsDeleted == false && x.DateStart.Month == DateTime.Now.Month,
orderBy: x => x.OrderBy(y => y.DateStart)
includes: new() { "Task", "ProductionOrder" } //(tried with/without including the navigation prop)
);
// The GetAllQueryable return the mapped IQueryable from EF Core DBContext, for the entity, and works fine (all the DB records list in queryable form)
int count = 0;
var result = PerformAllActionsSyncfusion(reports, dm, out count);
return dm.RequiresCounts ? Json(new { result, count = count }) : Json(result);
}
catch (Exception ex)
{
return StatusCode(500, ClientConstants.ERROR_INTERNAL_DEFAULT);
}
}
// In the "PerformAllActionsSyncfusion" method i perform all the sorting, filtering, paging action as you report in the documentation, with the same order and count, everything works fine excluding the filtering of complex objects, specifically the LINQ error reported appear here:
public IQueryable<T> PerformFilteringSyncfusion<T> (IQueryable<T> dataSource, DataManagerRequest dm) where T : class {
DataOperations operation = new DataOperations();
if (dm.Where != null && dm.Where.Count > 0) //Filter
dataSource = operation.PerformFiltering(dataSource, dm.Where, dm.Where[0].Operator);
return dataSource;
}
Hi Martino,
On inspecting the details and the code example provided, we suspect that you are facing issue, when you are filtering the datasource with complex Object data field on grid columns and get and error with the LINQ query in the EF core. The issue you have mentioned above is related to EF Core which has already been discussed in the below stack overflow thread.
Stack overflow: https://stackoverflow.com/questions/68737681/the-linq-expression-could-not-be-translated-either-rewrite-the-query-in-a-form
If you still face the issue, kindly share an issue reproducing sample, which will be helpful for us to validate the issue.
Hi Joseph,
I've found the solution time ago, sorry for the late response.
As you're saying, LINQ was unable to translate the conversion between DTOs and EF objects.
Actually I do have to pass the DataManagerRequest to the Service and apply the filters/sortings etc. on the IQueryable, before performing the projection of the mapping from EF obj to DTOs.
Below an example:
public async Task<(IQueryable<BankDTO>, int)> GetAllQueryableForSyncfusion(DataManagerRequest dm, Expression<Func<Bank, bool>> filter = null, Func<IQueryable<Bank>, IOrderedQueryable<Bank>> orderBy = null, List<string> includes = null)
{
try
{
int count = 0;
IQueryable<Bank> banks = await _unitOfWork.BankRepository.GetAllQueryable(filter, orderBy, includes);
banks = PerformAllActionsSyncfusion(banks, dm, out count).AsQueryable();
IQueryable<BankDTO> bankDTOs = banks.ProjectToType<BankDTO>(_mapper.Config);
return (bankDTOs, count);
}
catch (Exception ex)
{
AddError(ex.Message);
return (null, 0);
}
}
Thanks for your help, best regards.
Hi notMartino,
We are happy to hear that you resolved the reported query.
Please get back to us if you need any other assistance.
Regards,
Johnson Soundararajan S