Shakeel Hussain Mir
Shakeel Hussain Mir

Reputation: 286

While using generics, Linq expression could not be translated

im using generic in my C# code

   var _Entity = context.Set<T>()
                 .FirstOrDefault(r => (long)r.GetType().GetProperty("Id").GetValue(r, null) == Id);

This code line throwing exception

    (long)r.GetType().GetProperty("Id").GetValue(r, null) 

if i remove above line it will work absolutely fine.

exception message The LINQ expression 'DbSet\r\n .Where(f => (long)f.GetType().GetProperty("Id").GetValue(\r\n obj: f, \r\n index: null) == __model_Id_0)' 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 either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

one more thing adding .ToList() in the statement like this

    context.Set<T>().ToList()

makes it work but it creates performance isssues.

Upvotes: 0

Views: 249

Answers (1)

John
John

Reputation: 3182

All LINQ code uses the same syntax so all LINQ code will pass or fail the same when compiling. Whether or not your LINQ code will execute at run time, though, depends on the LINQ provider in use. If you're using EF then you're using the LINQ to Entities provider. That provider must be able to translate your LINQ code into SQL code to execute against the database. Hopefully you can understand why your code using Reflection would not be able to be translated to SQL. By calling ToList, you evaluate your LINQ to Entities query and get a local collection, so the subsequent FirstOrDefault call is using the LINQ to Objects provider. It doesn't need to translate anything, so Reflection is fine.

Basically, you need to get rid of that Reflection. You need to use specific types and member:

var _Entity = context.Set<MainEntity>().FirstOrDefault(r => r.Id == Id);

I suspect that the issue here is that your code is in a generic repository and MainEntity is a generic type parameter, rather than a concrete type. The solution to that would be to define an interface with an Id property and then have all your entities implement that interface. You can then add a generic type constraint to that parameter in your repository class and then MainEntity.Id will be valid.

Having said that, if I'm right about this code being in a repository then you're wrong from the outset. You should not implement the Repository pattern yourself when using EF. An EF context is a unit of work and each DbSet is a repository already, so you're just creating problems for yourself.

Upvotes: 2

Related Questions