Passing a predicate that was passed in as a parameter - c#

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.

Related

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)));
}

Create a LinQ Expression with another Expression's Parameters

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.

How can I implement NotOfType<T> in LINQ that has a nice calling syntax?

I'm trying to come up with an implementation for NotOfType, which has a readable call syntax. NotOfType should be the complement to OfType<T> and would consequently yield all elements that are not of type T
My goal was to implement a method which would be called just like OfType<T>, like in the last line of this snippet:
public abstract class Animal {}
public class Monkey : Animal {}
public class Giraffe : Animal {}
public class Lion : Animal {}
var monkey = new Monkey();
var giraffe = new Giraffe();
var lion = new Lion();
IEnumerable<Animal> animals = new Animal[] { monkey, giraffe, lion };
IEnumerable<Animal> fewerAnimals = animals.NotOfType<Giraffe>();
However, I can not come up with an implementation that supports that specific calling syntax.
This is what I've tried so far:
public static class EnumerableExtensions
{
public static IEnumerable<T> NotOfType<T>(this IEnumerable<T> sequence, Type type)
{
return sequence.Where(x => x.GetType() != type);
}
public static IEnumerable<T> NotOfType<T, TExclude>(this IEnumerable<T> sequence)
{
return sequence.Where(x => !(x is TExclude));
}
}
Calling these methods would look like this:
// Animal is inferred
IEnumerable<Animal> fewerAnimals = animals.NotOfType(typeof(Giraffe));
and
// Not all types could be inferred, so I have to state all types explicitly
IEnumerable<Animal> fewerAnimals = animals.NotOfType<Animal, Giraffe>();
I think that there are major drawbacks with the style of both of these calls. The first one suffers from a redundant "of type/type of" construct, and the second one just doesn't make sense (do I want a list of animals that are neither Animals nor Giraffes?).
So, is there a way to accomplish what I want? If not, could it be possible in future versions of the language? (I'm thinking that maybe one day we will have named type arguments, or that we only need to explicitly supply type arguments that can't be inferred?)
Or am I just being silly?
I am not sure why you don't just say:
animals.Where(x => !(x is Giraffe));
This seems perfectly readable to me. It is certainly more straight-forward to me than animals.NotOfType<Animal, Giraffe>() which would confuse me if I came across it... the first would never confuse me since it is immediately readable.
If you wanted a fluent interface, I suppose you could also do something like this with an extension method predicate on Object:
animals.Where(x => x.NotOfType<Giraffe>())
How about
animals.NotOf(typeof(Giraffe));
Alternatively, you can split the generic parameters across two methods:
animals.NotOf().Type<Giraffe>();
public static NotOfHolder<TSource> NotOf<TSource>(this IEnumerable<TSource> source);
public class NotOfHolder<TSource> : IHideObjectMembers {
public IEnumerable<TSource> NotOf<TNot>();
}
Also, you need to decide whether to also exclude inherited types.
This might seem like a strange suggestion, but what about an extension method on plain old IEnumerable? This would mirror the signature of OfType<T>, and it would also eliminate the issue of the redundant <T, TExclude> type parameters.
I would also argue that if you have a strongly-typed sequence already, there is very little reason for a special NotOfType<T> method; it seems a lot more potentially useful (in my mind) to exclude a specific type from a sequence of arbitrary type... or let me put it this way: if you're dealing with an IEnumerable<T>, it's trivial to call Where(x => !(x is T)); the usefulness of a method like NotOfType<T> becomes more questionable in this case.
If you're going to make a method for inference, you want to infer all the way. That requires an example of each type:
public static class ExtMethods
{
public static IEnumerable<T> NotOfType<T, U>(this IEnumerable<T> source)
{
return source.Where(t => !(t is U));
}
// helper method for type inference by example
public static IEnumerable<T> NotOfSameType<T, U>(
this IEnumerable<T> source,
U example)
{
return source.NotOfType<T, U>();
}
}
called by
List<ValueType> items = new List<ValueType>() { 1, 1.0m, 1.0 };
IEnumerable<ValueType> result = items.NotOfSameType(2);
I had a similar problem, and came across this question whilst looking for an answer.
I instead settled for the following calling syntax:
var fewerAnimals = animals.Except(animals.OfType<Giraffe>());
It has the disadvantage that it enumerates the collection twice (so cannot be used with an infinite series), but the advantage that no new helper function is required, and the meaning is clear.
In my actual use case, I also ended up adding a .Where(...) after the .OfType<Giraffe>() (giraffes also included unless they meet a particular exclusion condition that only makes sense for giraffes)
I've just tried this and it works...
public static IEnumerable<TResult> NotOfType<TExclude, TResult>(this IEnumerable<TResult> sequence)
=> sequence.Where(x => !(x is TExclude));
Am I missing something?
You might consider this
public static IEnumerable NotOfType<TResult>(this IEnumerable source)
{
Type type = typeof(Type);
foreach (var item in source)
{
if (type != item.GetType())
{
yield return item;
}
}
}

Accessing properties through Generic type parameter

I'm trying to create a generic repository for my models. Currently i've 3 different models which have no relationship between them. (Contacts, Notes, Reminders).
class Repository<T> where T:class
{
public IQueryable<T> SearchExact(string keyword)
{
//Is there a way i can make the below line generic
//return db.ContactModels.Where(i => i.Name == keyword)
//I also tried db.GetTable<T>().Where(i => i.Name == keyword)
//But the variable i doesn't have the Name property since it would know it only in the runtime
//db also has a method ITable GetTable(Type modelType) but don't think if that would help me
}
}
In MainViewModel, I call the Search method like this:
Repository<ContactModel> _contactRepository = new Repository<ContactModel>();
public void Search(string keyword)
{
var filteredList = _contactRepository.SearchExact(keyword).ToList();
}
Solution:
Finally went with Ray's Dynamic Expression solution:
public IQueryable<TModel> SearchExact(string searchKeyword, string columnName)
{
ParameterExpression param = Expression.Parameter(typeof(TModel), "i");
Expression left = Expression.Property(param, typeof(TModel).GetProperty(columnName));
Expression right = Expression.Constant(searchKeyword);
Expression expr = Expression.Equal(left, right);
}
query = db.GetTable<TModel>().Where(Expression.Lambda<Func<TModel, bool>>(expr, param));
Interface solution
If you can add an interface to your object you can use that. For example you could define:
public interface IName
{
string Name { get; }
}
Then your repository could be declared as:
class Repository<T> where T:class, IName
{
public IQueryable<T> SearchExact(string keyword)
{
return db.GetTable<T>().Where(i => i.Name == keyword);
}
}
Alternate interface solution
Alternatively you could put the "where" on your SearchExact method by using a second generic parameter:
class Repository<T> where T:class
{
public IQueryable<T> SearchExact<U>(string keyword) where U: T,IName
{
return db.GetTable<U>().Where(i => i.Name == keyword);
}
}
This allows the Repository class to be used with objects that don't implement IName, whereas the SearchExact method can only be used with objects that implement IName.
Reflection solution
If you can't add an IName-like interface to your objects, you can use reflection instead:
class Repository<T> where T:class
{
static PropertyInfo _nameProperty = typeof(T).GetProperty("Name");
public IQueryable<T> SearchExact(string keyword)
{
return db.GetTable<T>().Where(i => (string)_nameProperty.GetValue(i) == keyword);
}
}
This is slower than using an interface, but sometimes it is the only way.
More notes on interface solution and why you might use it
In your comment you mention that you can't use an interface but don't explain why. You say "Nothing in common is present in the three models. So i think making an interface out of them is not possible." From your question I understood that all three models have a "Name" property. In that case, it is possible to implement an interface on all three. Just implement the interface as shown and ", IName" to each of your three class definitions. This will give you the best performance for both local queries and SQL generation.
Even if the properties in question are not all called "Name", you can still use the nterface solution by adding a "Name" property to each and having its getter and setter access the other property.
Expression solution
If the IName solution won't work and you need the SQL conversion to work, you can do this by building your LINQ query using Expressions. This more work and is significantly less efficient for local use but will convert to SQL well. The code would be something like this:
class Repository<T> where T:Class
{
public IQueryable<T> SearchExact(string keyword,
Expression<Func<T,string>> getNameExpression)
{
var param = Expression.Parameter(typeof(T), "i");
return db.GetTable<T>().Where(
Expression.Lambda<Func<T,bool>>(
Expression.Equal(
Expression.Invoke(
Expression.Constant(getNameExpression),
param),
Expression.Constant(keyword),
param));
}
}
and it would be called thusly:
repository.SearchExact("Text To Find", i => i.Name)
Ray's method is quite good, and if you have the ability to add an interface definitely the superior however if for some reason you are unable to add an interface to these classes (Part of a class library you can't edit or something) then you could also consider passing a Func in which could tell it how to get the name.
EG:
class Repository<T>
{
public IQueryable<T> SearchExact(string keyword, Func<T, string> getSearchField)
{
return db.GetTable<T>().Where(i => getSearchField(i) == keyword);
}
}
You'd then have to call it as:
var filteredList = _contactRepository.SearchExact(keyword, cr => cr.Name).ToList();
Other than these two options you could always look into using reflection to access the Name property without any interface, but this has the downside that there's no compile-time check that makes sure the classes you're passing actually DO have a Name property and also has the side-effect that the LINQ will not be translated to SQL and the filtering will happen in .NET (Meaning the SQL server could get hit more than is needed).
You could also use a Dynamic LINQ query to achieve this SQL-side effect, but it has the same non type-safe issues listed above.

Categories