Create a LinQ Expression with another Expression's Parameters - c#

Vote my question to be closed
I have found a similar question and a really useful answer using
ExpressionVisitor class (Link:
How can I convert a lambda-expression between different (but compatible) models?).
Thank you all, I'm voting to my answer become closed as duplicate, please consider voting too.
Code
I'm developing a repository code that uses a Data Transfer Object, like the code below.
public class UsuarioRepositorio : IUsuarioRepository
{
private readonly MongoRepository<UsuarioDto> _Repository;
public UsuarioRepository(string connectionString)
{
_Repositorio = new MongoRepository<UsuarioDto>(connectionString, "");
}
}
public interface IUsuarioRepository
{
IEnumerable<T> Select(Expression<Func<Usuario, bool>> predicate);
}
UsuarioDto is the data transfer object for the Usuario class, both inheriting from the interface IUsuario.
The UsuarioRepository implements the IUsuarioRepository interface, and has a private member called _Repository, which belongs to the MongoRepository<UsuarioDto> type.
The _Repository member has a method called Select which accepts an argument of type Expression<Func<UsuarioDto, bool>>.
The IUsuarioRepository has a declared method called Select which accepts an argument of type Expression<Func<Usuario, bool>>.
Problem
The problem is that I need to implement the Select method in UsuarioRepository, using the IUsuarioRepository method signature and passing to _Repository a new expression of Expression<Func<UsuarioDto, bool>> type, with the same parameters of Expression<Func<Usuario, bool>> argument.
Basically I need a way to copy the expression parameters to a new expression of different type, knowing that the expressions has the same properties because they have the same interface inheritance. Something like this:
public IEnumerable<Usuario> Select(Expression<Func<Usuario, bool>> predicate)
{
Expression<Func<UsuarioDto, bool>> transferExpression = x => x != null;
transferExpression = transferExpression .Update(predicate.Body, predicate.Parameters);
return _Repository.Select(transferExpression ).ToList().Select(x => x.ToDomain());
}
Questions
The Update method of Expression type does work like the code above?
If it does not work, is there a way to copy expressions of different types, but with the same base/interface properties?
Thank you very much!

I have a blog post about combining 2 expressions of the same type here:
http://blog.waseem-sabjee.com/2013/07/23/linq-expression-how-to-append-to-an-expression-at-a-later-stage/
all you will need to do to achieve working with 2 types is alter the static methods in my extension class LambdaExtensions to work with T, T2 instead of T
a word of warning, if referencing a property of T2 that is not in T1, it may not be successful - you will need to handle this.
I've provided you with a starting point, and I will also be attempting this myself, I will update this answer later - but feel free to try it out yourself so long.

Related

Why can't I replace IEnumerable<T> by a generic type variable in extension method?

I am trying to make an extension method more generic to avoid redundancy (Here is an example of some real code, the code below is just to demonstrate the issue - I had the idea to make the method available for IQueryable<T> as well).
The following works fine:
public static class Extensions
{
public static IEnumerable<T> MySelect1<T, V>(this IEnumerable<T> query, Func<T, V> f)
{
// do something, then return IEnumerable<T>
var result=query.AsEnumerable<T>();
return result;
}
public static IQueryable<T> MySelect1<T, V>(this IQueryable<T> query, Func<T, V> f)
{
// do something, then return IQueryable<T>
var result = query.AsQueryable<T>();
return result;
}
}
I can use it in LinqPad like (when connected with the Northwind sample database):
var myQuery=(from x in Customers select x);
myQuery.AsEnumerable().MySelect1(d => d.CustomerID).Dump();
myQuery.AsQueryable().MySelect1(d => d.CustomerID).Dump();
Now I wanted to get rid of the duplicate implementation of MySelect1, so I refactored it as:
public static class Extensions
{
public static E MySelect2<E, T, V>(this E query, Func<T, V> f)
where E : System.Linq.IQueryable<T>, System.Collections.Generic.IEnumerable<T>
{
return (E)query.Select(f);
}
}
This compiles too, but I cannot use MySelect2 the same way as I did above, consider the following:
// CS0411 The type arguments for method 'Extensions.MySelect2<E, T, V>(E, Func<T, V>)'
// cannot be inferred from the usage. Try specifying the type arguments explicitly.
myQuery.AsEnumerable().MySelect2(d => d.CustomerID).Dump();
myQuery.AsQueryable().MySelect2(d => d.CustomerID).Dump();
Ok, doing what the error asks for works for this code line:
myQuery.AsQueryable()
.MySelect2<IQueryable<Customers>, Customers, String>(d => d.CustomerID).Dump();
but not for that one:
myQuery.AsEnumerable<Customers>()
.MySelect2<IEnumerable<Customers>, Customers, String>(d => d.CustomerID).Dump();
Here, I am getting
CS0311 The type 'System.Collections.Generic.IEnumerable<LINQPad.User.Customers>' cannot be used as type parameter 'E' in the generic type or method 'Extensions.MySelect2<E, T, V>(E, Func<T, V>)'. There is no implicit reference conversion from 'System.Collections.Generic.IEnumerable<LINQPad.User.Customers>' to 'System.Linq.IQueryable<LINQPad.User.Customers>'.
Why? And how can it be fixed? Please help.
Why?
For exactly the reason stated in the error message: you're trying to use IEnumerable<Customers> as the type argument for E, but E has this constraint:
where E : System.Linq.IQueryable<T>
And how can it be fixed?
It can't, assuming I understand what you're trying to achieve.
There's a fundamental problem with the "simplification" you're trying to achieve: you don't actually have full duplication in your original MySelect1 methods. The first calls AsEnumerable() and the second calls AsQueryable(). You're trying to replace those with a cast, and that's just not going to work.
There's a further problem, even with your original methods: you're accepting Func<T, V> f as a parameter for your queryable-based method, which means any time you call Select or similar and passing in f, you'll be calling Enumerable.Select instead of Queryable.Select. To really use IQueryable<> properly, you should accept Expression<Func<T, V>> f instead. At that point, you won't need to call AsQueryable anyway.
Your two methods "should" take radically different paths based on whether you're using LINQ to Objects or a different LINQ provider (e.g. LINQ to SQL), and that can't be hidden as a pure implementation detail without significant changes that would probably make it less useful than you want anyway.

Passing a predicate that was passed in as a parameter

I'm having trouble with passing in a predicate to another function. This predicate would have been passed in as a parameter that is trying to call the second function. Below is a code snippet.
public IEnumerable<ViewModel> BuildModel<TPart, TRecord>(Expression<Func<TRecord, bool>> predicate)
where TPart : ContentPart<TRecord>
where TRecord : ContentPartRecord
{
IEnumerable<ReportPart> items = GetList<ReportPart, ReportRecord>(predicate);
This issue is the predicate parameter, on the call to GetList() it keeps erroring, saying the call has some invalid arguments. The Get list call is:
public IEnumerable<TPart> GetList<TPart, TRecord>(Expression<Func<TRecord, bool>> predicate)
where TPart : ContentPart<TRecord>
where TRecord : ContentPartRecord
I been trying changing the parameter a bunch of different ways trying to get this to work but I haven't had any success. Maybe I'm not understanding why the compiler thinks that 'predicate' is different than what GetList() is expecting.
EDIT: more information
ReportPart : ContentPart<ReportRecord>
ReportRecord : ContentPartRecord
ContentPart and ContentPartRecord are both base classes
Caller to BuildModels
List<ReportViewModel> model = _service.BuildReports<ReportPart, ReportRecord>(x => x.Id == 1).ToList();
BuildModels
public IEnumerable<ReportViewModel> BuildReports<TPart, TRecord>(System.Linq.Expressions.Expression<Func<TRecord, bool>> predicate)
where TPart : ContentPart<TRecord>
where TRecord : ContentPartRecord
{
List<ReportViewModel> model = new List<ReportViewModel>();
IEnumerable<ReportPart> reportParts = GetList<ReportPart, ReportRecord>(predicate);
//do some stuff with reportParts
return model;
}
}
GetList
public IEnumerable<TPart> GetList<TPart, TRecord>(System.Linq.Expressions.Expression<Func<TRecord, bool>> filter)
where TPart : ContentPart<TRecord>
where TRecord : ContentPartRecord
{
return filter == null ?
Services.ContentManager.Query<TPart, TRecord>().List() :
Services.ContentManager.Query<TPart, TRecord>().Where(filter).List();
}
Without a good, minimal, complete code example, it's impossible to know for sure what the best fix for your problem is, assuming one exists at all.
That said, variance problems generally come in two flavors: 1) what you're doing is truly wrong and the compiler is saving you, and 2) what you're doing is not provably correct, so you have to promise the compiler you know what you're doing.
If you're in the first category, then all is lost. You can't get this to work.
But if you're in the second category, you may be able to get your call to work by wrapping the original predicate in a new one that is compatible with the called method's requirements:
IEnumerable<ReportPart> items =
GetList<ReportPart, ReportRecord>(r => predicate((TRecord)r));
That said, while it's possible that there's some important reason for you writing the code this way, given the little bit of code you've shown so far, it's not really clear why you're trying to take the generic predicate and force it into the specific type.
Depending on what's really going on in the rest of the code, a pair of generic methods like this would work better where you either 1) go fully generic (i.e. don't force the type as ReportRecord in the call to GetList()), or 2) you don't bother with the generic types at all (i.e. leave out TPart and TRecord from the BuildModel() method).
Example of 1):
public IEnumerable<ViewModel> BuildModel<TPart, TRecord>(
Expression<Func<TRecord, bool>> predicate)
where TPart : ContentPart<TRecord>
where TRecord : ContentPartRecord
{
IEnumerable<TPart> items = GetList<TPart, TRecord>(predicate);
}
Example of 2):
public IEnumerable<ViewModel> BuildModel(
Expression<Func<ReportRecord, bool>> predicate)
{
IEnumerable<ReportPart> items = GetList<ReportPart, ReportRecord>(predicate);
}
The mixing and matching, even if you can get it to work correctly, is often a sign that there's a more fundamental problem in the architecture, where generics are either being used where they shouldn't be, or are not being taken advantage as well as they should be.
If the above does not get you back on track, you really should improve the question by providing a minimal, complete code example.

Differences between repositories methods creation

Someone can tell me the difference between:
IQueryable<T> GetAll<T>();
and
IQueryable<T> GetAll();
What is the <T> after GetAll???
Well that makes a lot more sense. Please use code tags.
<T> is used to indicate a generic parameter, you can add any type to it (provided you don't violate any constraints, ofcourse).
Example:
var result1 = GetAll<string>();
var result2 = GetAll<int>();
Both will use the first method.
If you want to use the second, use
var result = GetAll();
MSDN on generics.
One reason why you could want this is this sample implementation:
IQueryable<T> GetAll<T>() {
return someDataContext.Users.OfType<T>();
}
called with
var managers = GetAll<Manager>();
Working sample:
void Main()
{
printTypes<string>();
}
static void printTypes<T>() {
var myList = new List<Object> {"string 1", "string 2", 5 };
foreach(var item in myList.OfType<T>()) {
Console.WriteLine (item);
}
}
Output
string 1
string 2
Both:
IQueryable<T> GetAll<T>();
and
IQueryable<T> GetAll();
make use of Generics.
GetAll<T>: The <T> in GetAll<T> is a generic method. T has
method level scope.
GetAll(): a non-generic method that returns a class level generic IQueryable<T>
GetAll is not a .NET framework method. Rather a custom definition in your repository code. Without the implementation of both methods no one can tell you which one to use for some given scenario. That being said, I expect a well written implementation to be interchangeable. If I had to guess, GetAll() may function as a stand in for generic type inference for a method without a parameter of type T. Then the caller can make a parameterless call to GetAll without specifying the type GetAll<Entity> per-se.

LINQ expression with generic class properties

I would like to pass an IQueryable and an array of ids to a method which filters the IQueryable based on those ids.
As the ids can be either long's or int's it should be solved generically.
I came up with the following:
public static IEnumerable<T> GetModified<TId, T>(IQueryable<T> objects, TId[] ids) where T : class
{
return objects.Where(j => ids.Contains((TId)j.GetType().GetProperty("Id").GetValue(j)));
}
Unfortunately I'm getting the exception:
LINQ to Entities does not recognize the method 'System.Object GetValue(System.Object)' method, and this method cannot be translated into a store expression.
The exception is normal, as getting properties through reflection is something that clearly cannot be translated to SQL.
One thing I would try is to create a generic interface that exposes an Id property of a given type:
public interface HasId<T> {
T Id { get; set; }
}
Now you could declare your entity as implementing HasId<int>, for example, if the Id was of type int.
The next step is to modify your method like so:
public static IEnumerable<T> GetModified<TId, T>
(IQueryable<T> objects, TId[] ids) where T : class, HasId<TId>
{
return objects.Where(j => ids.Contains(j.Id));
}
Note the added generic restriction: where T : class, HasId<TId>. This enables you to write the simplified j.Id, which returns a TId value, instead of resorting to reflection.
Please note that I haven't run or tested this code; it's just an idea that I got when I saw your problem and I hope it helps.
Update:
Here's another possible solution that doesn't require that you declare interfaces or change your classes in any way:
public static IEnumerable<T> GetModified<TId, T>
(IQueryable<T> objects, TId[] ids, Expression<Func<T, TId>> idSelector)
where T : class
{
return objects.Where(j => ids.Contains(idSelector(j)));
}
What I've done here is add the Expression<Func<T, TId>> idSelector parameter, an expression that can return the Id of a given instance of T.
You would call the method like that:
var modified = GetModified(dbObjects, yourIdArray, entity => entity.Id);
(only the third parameter being new; keep the others as you have them now).
Again, I haven't tested if this works or even compiles, as I don't have a computer with VS here :(.
Entity Framework doesn't support some of the .NET methods such as GetValue() since it does not translate to SQL (which is the code actually executed to the IQueryable. Try calling ToList to get the CLR object before doing reflection:
public static IEnumerable<T> GetModified<TId, T>(IQueryable<T> objects, TId[] ids) where T : class
{
return objects.ToList().Where(j => ids.Contains((TId)j.GetType().GetProperty("Id").GetValue(j)));
}

Can I achieve covariance in .NET 3.5, C#

I have class X that implements an interface IX. I also have a repository class dedicated for X, which uses lambda expresions as parameters:
public interface IX
{
}
public class X : IX
{
....
}
public class XRepository : IRepository<X>
{
public IEnumerable<X> Filter(Func<X, bool> filterFunc)
{
...
}
}
I need to make the repository class work with the interface IX, therefore I add IRepository<IX> to the interfaces being implemented:
public class XRepository : IRepository<X>, IRepository<IX>
{
public IEnumerable<X> Filter(Func<X, bool> filterFunc)
{
...
}
public IEnumerable<IX> Filter(Func<IX, bool> filterFunc)
{
// I need to call the same filter method as above, but
// in order to do so I must convert the Func<IX, bool> to Func<X, bool>.
}
}
I must convert the Func<IX, bool> to Func<X, bool>, but since the code is written in C# 3.0 using .NET 3.5, I cannot benefit from Type covariance, which was introduced in 4.0.
A simple solution could be to use Func<X, bool> newFunc = x => filterFunc(x);, where filterFunc is of type Func<IX, bool>. This would compile and one might expect it to run fine, but I assume it will not. The problem is that I am using 3rd party framework for the filter implementation, namely FluentNhibernate. I know it uses expression trees to strip the passed into the lambda expression member access condition (like x => x.Name == "John") in order to build native SQL query (like WHERE Name = 'John'). The above solution would produce a Func<X, bool> that is not such expression and I fear it will fail to translate. So I need to create the same lambda expression but with the compatible type. Knowing that X implements IX, it is obvious that any code inside a Func<IX, bool> will work for objects of type X. It is not obvious for me, however, how can I perform this conversion.
I assume this can be done using expression trees. I also fear my performance will suffer greatly. Even if I decide to have another solution to my scenario, I will still appreciate the suggested way to translate one lambda into a similar another.
Edit:
To clarify more about the issue I am experiencing, I wrote the following test, simulating the real-life scenarion I am facing:
Func<IX, bool> filter = y => y.Name == "John";
Func<X, bool> compatibleFilter = y => filter(y);
...
// Inside the Filter(Func<X, bool> filter method)
using(var session = nhibernateSessionFactory.OpenSession())
{
IEnumerable<X> xx = session.Query<X>().Where(z => compatibleFilter(z)).ToList();
}
so, at the ToList() method I receive the following exception
Unable to cast object of type 'NHibernate.Hql.Ast.HqlParameter' to type 'NHibernate.Hql.Ast.HqlBooleanExpression'.
This confirms my assumption that Flunet NHiberante cannot correctly handle the compatibleFilter argument.
So what I want is a way to convert the Func to Func or as suggested by John Skeet, an Expression<Func<IX, bool>> to an Expression<Func<X, bool>> which have the same body (y => y.Name = "John").
Edit 2:
Finally I made it happen! The correct way is not to use Func<X, bool>, but Expression<Func<X, bool>>.
Expression<Func<IX, bool>> filter = y => y.Name == "John Skeet";
Expression<Func<X, bool>> compatibleFilter = Expression.Lambda<Func<X, bool>>(
filter.Body,
filter.Parameters);
This produces the correct SQL query.IX, bool
A simple solution could be to use Func<X, bool> newFunc = x => filterFunc(x); where filterFunc is of type Func<IX, bool>. This would compile and one might expect it to run fine, but I assume it will not.
Why assume, when you can test? It should work absolutely fine. After all, you're passing an argument of type X for a parameter of type IX, which causes no type safety concerns.
You'll then need to convert from IEnumerable<X> to IEnumerable<IX>, which can be done with Cast for instance:
public IEnumerable<IX> Filter(Func<IX, bool> filterFunc)
{
Func<X, bool> newFilter = x => filterFunc(x);
return Filter(newFilter).Cast<IX>();
}
why do you use your concrete type isnt IX enough:
public class IXRepository : IRepository<IX>
{
public IEnumerable<X> Filter(Func<IX, bool> filterFunc)
{
...
}
}
As i understand it correctly, covariance is a language feature. So it does not depend directly on .net 4.

Categories