Reputation: 74
I don't want all columns to be returned so I'm trying to select some columns from EMPLOYEES, I got an error when running the following code:
var query = db.EMPLOYEES.AsQueryable();
query = ApplyFilter(query, filter);
var result = query.Select(x => new EMPLOYEE_DTO()
{
PHONE_NO = x.PHONE_NO,
EMAIL = x.EMAIL,
EMP_NO = x.EMP_NO
}).ToList();
private IQueryable<EMPLOYEE> ApplyFilter(IQueryable<EMPLOYEE> query, EmployeesFilter filter)
{
if (!string.IsNullOrEmpty(filter.EMAIL))
query = query.Where(u => u.EMAIL.ToLower().Contains(filter.EMAIL.ToLower()));
return query;
}
The error is: {"Unable to create a null constant value of type 'System.Collections.Generic.List`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'. Only entity types, enumeration types or primitive types are supported in this context."}
I saw a post saying that using DTO object (EMPLOYEE_DTO) will solve the issue but the issue still exist.
Please advice.
Upvotes: 0
Views: 105
Reputation: 30464
You don't tell us a lot about your classes. I assume that filter
is an EmployeesFilter
object in your local process; db
is an object of type DbContext
; and db.Employees
is an object of DbSet<Employee>
.
Both filter
and Employee
have a string property Email
Every DbSet<Employee>
implements IQueryable<Employee>
. So why are you calling AsQueryable
?
Your filter
is a local variable. In this context only filter.Email
is important. If the value of this property equals null, you want all Employees
, otherwise you want a subset of the Employees
, namely only those Employees
that have an Email
value equal to the Email
value in filter, ignoring Case.
Now ignoring case is always dangerous. After all, not everyone has names with only letters A-Z and a-z. It is better to describe what case ignorance you want: ordinal? current culture? invariant culture?
It seems you want the following:
var query = String.IsNullOrEmpty(filter.Email) ?
db.Employees :
db.Employees
.Where(employee => String.Equals(employee.Email, filter.Email,
StringComparison.InvariantCultureIgnoreCase);
I'm not sure if changing this into an extra function like ApplyFilter would improve readability, but if you really want, write it as an extension function for IQueryable<Employee>
:
static IQueryable<Employee> ApplyFilter(this IQueryable<Employee> employees,
EmployeeFilter filter)
{
return String.IsNullOrEmpty(filter.Email) ?
employees :
employees.Where(employee => String.Equals(employee.Email, filter.Email,
StringComparison.InvariantCultureIgnoreCase);
}
Usage for any query:
IQueryable<Employee> someEmployees = ...
IQueryable<Employee> filteredEmployees = someEmployees.Filter(myFilter);
I deliberately didn't use var
, so you could see what happens to the types.
TODO: check if this code is correct by adding ToList()
to see if the Employees
can be fetched. But of course you already did that, didn't you?
Now your second part. So you have a query that returns an IQueryable<Employee>
and you want to project every Employee
into an EmployeeDto
. If you want to do this in your query, you'll have to make sure that your EmployeeDto
is a POCO: a class with a default constructor and only get / set properties.
If that is the case you should be able to perform your projection:
var result = query.Select(employee => new EMPLOYEE_DTO()
{
PHONE_NO = employee.PHONE_NO,
EMAIL = employee.EMAIL,
EMP_NO = employee.EMP_NO,
})
.ToList();
Upvotes: 0