Issue while using Except Extension Method - linq

What is the problem with the code below?
var newContextElementCollection = new List<NewContextElements>();
var res = from eleCollection in newContextElementCollection
where eleCollection.Property.Except(new List<string> { "Password", "Some Other Value" })
select eleCollection;
The NewContextElementCollection class:
public class NewContextElements
{
public string Property { get; set; }
public string Value { get; set; }
}
I am getting this error:
Instance argument: cannot convert from 'string' to
'System.Linq.IQueryable'
Error 2 'string' does not contain a definition for 'Except' and the best extension
method overload 'System.Linq.Queryable.Except(System.Linq.IQueryable,
System.Collections.Generic.IEnumerable)' has some invalid arguments

Property is a string, not an IEnumerable<string>, which is what your Except clause can work on.
var res= from eleCollection in newContextElementCollection
where eleCollection.Property != "Password"
select eleCollection;

var excluded = new List<string> { "Password","Some Other Value" };
var res = newContextElementCollection.Where(m => !excluded.Contains(m.Property));

Related

Linq to Sql Using a function to set a value

I wanted to get from a database a IEnumerable<T> and within the 'Select' method using a function to return a string value. But I always get back the
'method cannot be translated into a store expression'
error.
I already took a look all the post on Stack Overflow about the error 'LINQ to Entities does not recognize the method .... and this method cannot be translated into a store expression"
The only way that I found to get around this error is apply the function after the query has run.
void Main()
{
int eventId = 17;
IEnumerable<OccurrenceDropDownList> model = Occurrences.Select (s => new OccurrenceDropDownList
{
OccurrenceId = s.OccurrenceId,
Name = s.Name
})
.AsEnumerable()
.Select(m => new OccurrenceDropDownList
{
OccurrenceId = m.OccurrenceId,
Name = m.Name,
Selected = setSelected(m.OccurrenceId, eventId)
}).AsEnumerable();
foreach(var item in model)
{
Console.WriteLine(item.Name + " - id : " + item.OccurrenceId + " " + item.Selected);
}
}
public class OccurrenceDropDownList
{
public int OccurrenceId { get; set; }
public string Name { get; set; }
public string Selected { get; set; }
}
static string setSelected(int occurrence, int selectedid){
if(occurrence == selectedid){
return "selected";
}
return "";
}
Is there any way to apply the function as result of the first query?
It should be simplier:
int eventId = 17;
IEnumerable<OccurrenceDropDownList> model = Occurrences
.Select(s => new OccurrenceDropDownList
{
OccurrenceId = s.OccurrenceId,
Name = s.Name,
//magic ternary if
Selected = (eventId == s.OccurrenceId) ? "selected" : String.Empty
});
That's all. I used ternary if operator that should be translated to SQL.

Building a query (LINQ) with a sub-query

For simplicity sake lets assume I have the following two classes:
public class ComplexClass
{
public List<SubClass> SubClasses { get; set; }
public string Name { get; set; }
}
public class SubClass
{
public string Name { get; set; }
}
I have a List<ComplexClass> and I need to build a query based on some parameters.
It's an easy task if all I need to do is use the Name property of ComplexClass. Here's an example:
static IQueryable<ComplexClass> GetQuery(string someParameter, string someOtherParameter)
{
var query = list.AsQueryable();
if (!String.IsNullOrEmpty(someParameter))
query = query.Where(c => c.Name.StartsWith(someParameter));
if (!String.IsNullOrEmpty(someOtherParameter))
query = query.Where(c => c.Name.EndsWith(someOtherParameter));
return query;
}
Based on the parameters I have I can add more query elements. Of course the above example is simple, but the actual problem contains more parameters, and that number can grow.
Things aren't as simple if I want to find those ComplexClass instances which have SubClass instances which meet criteria based on parameters:
static IQueryable<ComplexClass> GetSubQuery(string someParameter, string someOtherParameter)
{
var query = list.AsQueryable();
if (!String.IsNullOrEmpty(someParameter))
if (!String.IsNullOrEmpty(someOtherParameter))
return query.Where(c => c.SubClasses.Where(sc => sc.Name.StartsWith(someParameter) && sc.Name.EndsWith(someOtherParameter)).Any());
else
return query.Where(c => c.SubClasses.Where(sc => sc.Name.StartsWith(someParameter)).Any());
else
if (!String.IsNullOrEmpty(someOtherParameter))
return query.Where(c => c.SubClasses.Where(sc => sc.Name.EndsWith(someOtherParameter)).Any());
else
return null;
}
I can no longer just add bits of the query based on each parameter, I now need to write the whole query in one go, and this means I need to check every combination of parameters, which is hardly ideal.
I suspect the key is to build an Expression class and create a lambda expression from that, but I'm not sure how to tackle the problem.
Any suggestions? :)
EDIT:
My initial idea was this:
static IQueryable<ComplexClass> GetSubQuery(string someParameter, string someOtherParameter)
{
var query = list.AsQueryable();
query = query.Where(c =>
{
var subQuery = c.SubClasses.AsQueryable();
if (!String.IsNullOrEmpty(someParameter))
subQuery = subQuery.Where(sc => sc.Name.StartsWith(someParameter));
if (!String.IsNullOrEmpty(someOtherParameter))
subQuery = subQuery.Where(sc => sc.Name.EndsWith(someOtherParameter));
return subQuery.Any();
});
return query;
}
This works in my small console test application as it's using LINQ to Objects. Unfortunately, I need to use Entity Framework and LINQ to Entities, which causes an implementation similar to the one above to throw a A lambda expression with a statement body cannot be converted to an expression tree error message.
I'm assuming that in you real-life code the SubClasses property is IQueryable<SubClass> rather than List<SubClass>?
If so, then your query building becomes easy:
static IQueryable<ComplexClass> GetSubQuery(
string someParameter, string someOtherParameter)
{
var query = list.AsQueryable();
if (!String.IsNullOrEmpty(someParameter))
query = query.Where(c => c.SubClasses
.Where(sc => sc.Name.StartsWith(someParameter)).Any());
if (!String.IsNullOrEmpty(someOtherParameter))
query = query.Where(c => c.SubClasses
.Where(sc => sc.Name.StartsWith(someOtherParameter)).Any());
return query;
}
Mixing IEnumerable<T> and IQueryable<T> using AsQueryable() is never a good idea.
I implemented my solution in a simple Console Project:
internal class Program
{
#region Constants and Fields
private static readonly List<ComplexClass> list = new List<ComplexClass>
{
new ComplexClass
{
Name = "complex",
SubClasses = new List<SubClass>
{
new SubClass
{
SubName = "foobar"
}
}
},
new ComplexClass
{
Name = "complex",
SubClasses = new List<SubClass>
{
new SubClass
{
SubName = "notfoobar"
}
}
}
};
#endregion
#region Public Methods
public static void Main(string[] args)
{
Console.WriteLine("foo / bar :");
GetSubQuery("foo", "bar");
Console.WriteLine();
Console.WriteLine("foo / null :");
GetSubQuery("foo", null);
Console.WriteLine();
Console.WriteLine("string.Empty / bar :");
GetSubQuery(string.Empty, "bar");
Console.WriteLine();
Console.WriteLine("maeh / bar :");
GetSubQuery("maeh", "bar");
Console.ReadKey();
}
#endregion
#region Methods
private static void GetSubQuery(string startsWith,
string endsWith)
{
var query = from item in list
let StartIsNull = string.IsNullOrEmpty(startsWith)
let EndIsNull = string.IsNullOrEmpty(endsWith)
where
(StartIsNull || item.SubClasses.Any(sc => sc.SubName.StartsWith(startsWith)))
&& (EndIsNull || item.SubClasses.Any(sc => sc.SubName.EndsWith(endsWith)))
select item;
foreach (var complexClass in query)
{
Console.WriteLine(complexClass.SubClasses.First().SubName);
}
}
#endregion
public class ComplexClass
{
#region Public Properties
public string Name { get; set; }
public List<SubClass> SubClasses { get; set; }
#endregion
}
public class SubClass
{
#region Public Properties
public string SubName { get; set; }
#endregion
}
}
The Console Output is:
foo / bar :
foobar
foo / null :
foobar
string.Empty / bar :
foobar
notfoobar
maeh / bar :

No generic method 'Where' on type 'System.Linq.Queryable' is compatible with the supplied type arguments and arguments

I want to retrieve a specific record using IQueryable. But i get error 'No generic method 'Where' on type 'System.Linq.Queryable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic.'. I got the selected row id, but I cannot display it out. Here is my code.
internal static IQueryable GetRecordsFromPrimaryKeys(this IQueryable datasource, List<FilterDescriptor> primaryKeys)
{
IQueryable data = datasource;
ParameterExpression paramExp = null;
bool firstLoop = false;
System.Linq.Expressions.Expression predicate = null;
var RecordType = datasource.GetObjectType();
paramExp = RecordType.Parameter();
foreach (FilterDescriptor primaryKey in primaryKeys)
{
if (!(firstLoop))
{
predicate = data.Predicate(paramExp, primaryKey.ColumnName, primaryKey.Value, FilterType.Equals, false, RecordType);
firstLoop = true;
}
else
{
predicate = predicate.AndPredicate(data.Predicate(paramExp, primaryKey.ColumnName, primaryKey.Value, FilterType.Equals, false, RecordType));
}
}
if (paramExp != null && predicate != null)
{
var lambda = Expression.Lambda(predicate, paramExp);
data = data.Provider.CreateQuery(
Expression.Call(
typeof(Queryable),
"Where",
new Type[] { data.ElementType },
data.Expression,
lambda
)
);
}
return data;
}
My Code works well for IEnumerable/IQueryable/ICollection . But it throws the exception when i specify the class with the keyword virtual and type as ICollection. My code is
public class RoomType
{
public int ID { get; set; }
[MaxLength(10, ErrorMessage = "Room code cannot be longer than 10 characters.")]
public string Code { get; set; }
[MaxLength(50, ErrorMessage = "Room name cannot be longer than 50 characters.")]
public string Name { get; set; }
public virtual ICollection<RoomCategory> RoomCategories { get; set; }
}
Some random values gets appended to 'RecordType' while using the keyword 'virtual'. I think this leads to the exception. Still searching for the solution.
I don't know what is going wrong . Any suggestions welcome.
Thanks.
I just ran into a similar situation. The problem stems from the fact that in some cases you're dealing with the "proxy" not the actual entity. So, you want to make sure that RecordType matches data.ElementType.
try:
var recordType = datasource.GetObjectType();
// make sure we have the correct type (not the proxy)
if (recordType.BaseType.Name != "Object")
recordType = recordType.BaseType;
Or better yet, try:
var recordType = data.ElementType
Try to use typeof(Enumerable) instead of typeof(Queryable)

Linq expression over a list of derived types

I am trying to write a Linq expression that checks against property in a derived class, but the list is made up of members from a base class. Example code below. The 2nd line of the Process method starting with 'var list' does not compile, but I am not sure what syntax I should use to make it valid?
public class Manager
{
public void Process()
{
Base[] stuff = { new Derived() { Id = "1", Name = "me" } };
var list = stuff.Where<Derived>(d => d.Name == "me");
}
}
public class Base
{
public string Id { get; set; }
}
public class Derived : Base
{
public string Name { get; set; }
}
If you know the list has only Derived, you can use the Cast<T> method:
var list = stuff.Cast<Derived>().Where(d => d.Name == "me");
If there are only some Derived, you can use OfType<T>:
var list = stuff.OfType<Derived>().Where(d => d.Name == "me");
In that case, the non-Derived objects will be skipped.

How do I create a custom Select lambda expression at runtime to work with sub classes

If I have following type hierarchy:
abstract class TicketBase
{
public DateTime PublishedDate { get; set; }
}
class TicketTypeA:TicketBase
{
public string PropertyA { get; set; }
}
class TicketTypeB:TicketBase
{
public string PropertyB { get; set; }
}
and many more TicketTypes : TicketBase
and want to create a function which selects any property e.g. PropertyA from any ticket type e.g. TicketTypeA
I wrote this function:
private Func<TicketBase, String> CreateSelect(Type t, String FieldName)
{
var parameterExp = Expression.Parameter(t, "sel");
var fieldProp = Expression.PropertyOrField(parameterExp, FieldName);
var lambda = Expression.Lambda<Func<TicketBase, String>>(fieldProp, parameterExp);
return lambda.Compile();
}
and call it on a List<TicketBase> Tickets like so:
Type typeToSelectFrom = typeof(TicketTypeA);
String propertyToSelect = "PropertyA";
Tickets.Select(CreateSelect(typeToSelectFrom, propertyToSelect));
I get the following ArgumentException:
ParameterExpression of type 'TicketTypes.TicketTypeA' cannot be used for delegate parameter of type 'Types.TicketBase'
Anyone know how to fix this?
Well, one option is to include a cast, e.g.
private Func<TicketBase, String> CreateSelect(Type t, String FieldName)
{
var parameterExp = Expression.Parameter(typeof(TicketBase), "sel");
var cast = Expression.Convert(parameterExp, t);
var fieldProp = Expression.PropertyOrField(cast, FieldName);
var lambda = Expression.Lambda<Func<TicketBase, String>>(fieldProp,
parameterExp);
return lambda.Compile();
}
So that calling CreateSelect(typeof(TicketTypeA), "PropertyA") is equivalent to:
Func<TicketBase, string> func = tb => ((TicketTypeA)tb).PropertyA;
Obviously that's going to fail if you apply it to a TicketBase value which refers to (say) a TicketTypeB, but it's hard to avoid that, if you've got a List<TicketBase> or something similar.

Resources