Get IQueryable result view value in arraylist - linq

My code:
IQueryable grpdRows;
grpdRows = dtInput
.Select("", "partno")
.AsQueryable()
.GroupBy("new (iif(it[\"partno\"] == null, \"\", it[\"partno\"]) as GrpKey1)","it")
.Select("new (it.Key.GrpKey1 as GrpKey1, it.Count() as TotalCount")");
I need to get "grpdRows" resuls view in an arrayList.

I think this snippet may help you:
IList<string> list = new List<string>
{
"Value1",
"Value2",
"Value3",
"Value4"
};
IQueryable query = list.AsQueryable();
ArrayList arrayList = new ArrayList(query.Cast<string>().ToList());
You provided insufficient code so I did my example with string instead.

Related

How to handle null in LINQ query for nullable int if value not found

Here i am using simple list and one of the ageto string column is null
I am check in linq query if value not found then to return null. But value cannot be null error is coming up
var list = new[]
{
new { AgeFrom = "0", AgeTo="24"},
new { AgeFrom = "70", AgeTo= (string)null}
}.ToList();
var result = from r in list
select new EmployeeDTO
{
//AgeFrom Column is int? in DTO
AgeFrom = Convert.ToInt32(r.AgeFrom),
//AgeTo Column is int? in DTO
AgeTo = Convert.ToInt32(r.AgeTo ?? null)
}
Try this:
AgeTo = String.IsNullOrEmpty(r.AgeTo) ? (int?)null : (int?)Convert.ToInt32(r.AgeTo);
Which makes your code:
var list = new[]
{
new { AgeFrom = "0", AgeTo="24"},
new { AgeFrom = "70", AgeTo= (string)null}
}.ToList();
var result = from r in list
select new EmployeeDTO
{
//AgeFrom Column is int? in DTO
AgeFrom = Convert.ToInt32(r.AgeFrom),
//AgeTo Column is int? in DTO
String.IsNullOrEmpty(r.AgeTo) ? (int?)null : (int?)Convert.ToInt32(r.AgeTo)
};
Convert.ToInt32 can not convert null to an integer, that will always throw an exception.
One option would be to change:
AgeTo = Convert.ToInt32(r.AgeTo ?? null)
to:
AgeTo = r.AgeTo != null ? Convert.ToInt32(r.AgeTo) : null
The statement r.AgeTo ?? null is an example of the null-coalescing operator, which, in your case, is essentially saying that if r.AgeTo is null, then use null instead. As this isn't what you were trying to achieve, you are in fact passing null into Convert.ToInt32, which is causing your error.

Find the linq statement from an IQueryable<T>

If we do a .ToString() on a Linq expressiontree, we get a reprensentation of the actual code. Similarly is there a way to get the actual linq expression if you have access to an implementation of IQueryable?
In other words suppose I have this
var cars = new List<Car> { new Car { name = "Ford" }, new Car { name = "Merc"}, new Car { name = "Toyota" } };
var myCar = cars.Where(c => c.name =="Ford").AsQueryable();
How do I do this
var originalQuery=myCar.ToString() // I expect cars.Where(c => c.name =="Ford")

Dynamically Sorting with LINQ

I have a collection of CLR objects. The class definition for the object has three properties: FirstName, LastName, BirthDate.
I have a string that reflects the name of the property the collection should be sorted by. In addition, I have a sorting direction. How do I dynamically apply this sorting information to my collection? Please note that sorting could be multi-layer, so for instance I could sort by LastName, and then by FirstName.
Currently, I'm trying the following without any luck:
var results = myCollection.OrderBy(sortProperty);
However, I'm getting a message that says:
... does not contain a defintion for 'OrderBy' and the best extension method overload ... has some invalid arguments.
Okay, my argument with SLaks in his comments has compelled me to come up with an answer :)
I'm assuming that you only need to support LINQ to Objects. Here's some code which needs significant amounts of validation adding, but does work:
// We want the overload which doesn't take an EqualityComparer.
private static MethodInfo OrderByMethod = typeof(Enumerable)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(method => method.Name == "OrderBy"
&& method.GetParameters().Length == 2)
.Single();
public static IOrderedEnumerable<TSource> OrderByProperty<TSource>(
this IEnumerable<TSource> source,
string propertyName)
{
// TODO: Lots of validation :)
PropertyInfo property = typeof(TSource).GetProperty(propertyName);
MethodInfo getter = property.GetGetMethod();
Type propType = property.PropertyType;
Type funcType = typeof(Func<,>).MakeGenericType(typeof(TSource), propType);
Delegate func = Delegate.CreateDelegate(funcType, getter);
MethodInfo constructedMethod = OrderByMethod.MakeGenericMethod(
typeof(TSource), propType);
return (IOrderedEnumerable<TSource>) constructedMethod.Invoke(null,
new object[] { source, func });
}
Test code:
string[] foo = new string[] { "Jon", "Holly", "Tom", "William", "Robin" };
foreach (string x in foo.OrderByProperty("Length"))
{
Console.WriteLine(x);
}
Output:
Jon
Tom
Holly
Robin
William
It even returns an IOrderedEnumerable<TSource> so you can chain ThenBy clauses on as normal :)
You need to build an Expression Tree and pass it to OrderBy.
It would look something like this:
var param = Expression.Parameter(typeof(MyClass));
var expression = Expression.Lambda<Func<MyClass, PropertyType>>(
Expression.Property(param, sortProperty),
param
);
Alternatively, you can use Dynamic LINQ, which will allow your code to work as-is.
protected void sort_grd(object sender, GridViewSortEventArgs e)
{
if (Convert.ToBoolean(ViewState["order"]) == true)
{
ViewState["order"] = false;
}
else
{
ViewState["order"] = true;
}
ViewState["SortExp"] = e.SortExpression;
dataBind(Convert.ToBoolean(ViewState["order"]), e.SortExpression);
}
public void dataBind(bool ord, string SortExp)
{
var db = new DataClasses1DataContext(); //linq to sql class
var Name = from Ban in db.tbl_Names.AsEnumerable()
select new
{
First_Name = Ban.Banner_Name,
Last_Name = Ban.Banner_Project
};
if (ord)
{
Name = BannerName.OrderBy(q => q.GetType().GetProperty(SortExp).GetValue(q, null));
}
else
{
Name = BannerName.OrderByDescending(q => q.GetType().GetProperty(SortExp).GetValue(q, null));
}
grdSelectColumn.DataSource = Name ;
grdSelectColumn.DataBind();
}
you can do this with Linq
var results = from c in myCollection
orderby c.SortProperty
select c;
For dynamic sorting you could evaluate the string i.e. something like
List<MyObject> foo = new List<MyObject>();
string sortProperty = "LastName";
var result = foo.OrderBy(x =>
{
if (sortProperty == "LastName")
return x.LastName;
else
return x.FirstName;
});
For a more generic solution see this SO thread: Strongly typed dynamic Linq sorting
For this sort of dynamic work I've been using the Dynamic LINQ library which makes this sort of thing easy:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
http://msdn2.microsoft.com/en-us/vcsharp/bb894665.aspx
You can copy paste the method I post in that answer, and change the signature/method names:
How to make the position of a LINQ Query SELECT variable
You can actually use your original line of code
var results = myCollection.OrderBy(sortProperty);
simply by using the System.Linq.Dynamic library.
If you get a compiler error (something like cannot convert from or does not contain a definition...) you may have to do it like this:
var results = myCollection.AsQueryable().OrderBy(sortProperty);
No need for any expression trees or data binding.
You will need to use reflection to get the PropertyInfo, and then use that to build an expression tree. Something like this:
var entityType = typeof(TEntity);
var prop = entityType.GetProperty(sortProperty);
var param = Expression.Parameter(entityType, "x");
var access = Expression.Lambda(Expression.MakeMemberAccess(param, prop), param);
var ordered = (IOrderedQueryable<TEntity>) Queryable.OrderBy(
myCollection,
(dynamic) access);

how to query the settingspropertyvaluecollection

I have a settingspropertyvaluecollection.I dont want to loop through all the properties using a for each loop.Instead i want to query the collection.How do i do that?is there a way to use LINQ and do it?
Thanks
SettingsPropertyValueCollection doesn't implement IEnumerable<T> but it does implement IEnumerable. If you want to query it using LINQ you have a couple of options.
You could create a Where() extension method that takes IEnumerable and a query and performs the query for you:
public static class IEnumerableExtensions
{
public static IEnumerable<T> Where<T>(this IEnumerable input, Func<T,bool> query)
{
return input.Cast<T>().Where(item => query(item));
}
}
assuming:
var settings = new SettingsPropertyValueCollection
{
new SettingsPropertyValue(new SettingsProperty("Email")
{
DefaultValue = "a#a.com",
PropertyType = typeof(string)
}),
new SettingsPropertyValue(new SettingsProperty("City")
{
DefaultValue = "Austin",
PropertyType = typeof(string)
}),
new SettingsPropertyValue(new SettingsProperty("State")
{
DefaultValue = "TX",
PropertyType = typeof(string)
})
};
usage would be:
var matches = settings.Where<SettingsPropertyValue>(x => x.Name == "City")
alternatively you could use the LINQ Cast<T> operator to query the settings:
var matches = settings.Cast<SettingsPropertyValue>()
.Where(x => x.Name == "City");
if you expect only one possible match then use FirstOrDefault() instead of Where()
var match = settings.Cast<SettingsPropertyValue>()
.FirstOrDefault(x => x.Name == "City");
It's been a while since the question was answered and many things have changed since then.
You could cast the SettingsPropertyValueCollection to a list (or other container) and query it right away.
So, this would be my solution nowadays:
SettingsPropertyValueCollection settings = Properties.Settings.Default.PropertyValues
settings.Cast<SettingsPropertyValue>().ToList().Where(p => p.Name == "myProperty");

How to implement outer join expression tree?

I need to implement the query using expressions syntax (because I don't know types in compile time). For example query like this one:
from customer in Customers
join purchase in Purchases
on customer.ID equals purchase.CustomerID
into outerJoin
from range in outerJoin.DefaultIfEmpty()
where
customer.Name == "SomeName" &&
range.Description.Contains("SomeString") &&
customer.ID == range.CustomerID
select
new { Customer = customer, Purchase = range }
I found way to implement group join part like this:
ITable p = _dataContext.GetTable(typeof(Purchases));
ITable c = _dataContext.GetTable(typeof(Customers));
LambdaExpression outerSelectorLambda = DynamicExpression.ParseLambda(typeof(Customers), null, "ID");
LambdaExpression innerSelectorLambda = DynamicExpression.ParseLambda(typeof(Purchases), null, "CustomerID");
ParameterExpression param1 = Expression.Parameter(typeof(Customers), "customer");
ParameterExpression param2 = Expression.Parameter(typeof(IEnumerable<Purchases>), "purchases");
ParameterExpression[] parameters = new ParameterExpression[] { param1, param2 };
LambdaExpression resultsSelectorLambda = DynamicExpression.ParseLambda(parameters, null, "New(customers as customers, purchases as purchases)");
MethodCallExpression joinCall =
Expression.Call(
typeof(Queryable),
"GroupJoin",
new Type[] {
typeof(Customers),
typeof(Purchases),
outerSelectorLambda.Body.Type,
resultsSelectorLambda.Body.Type
},
c.Expression,
p.Expression,
Expression.Quote(outerSelectorLambda),
Expression.Quote(innerSelectorLambda),
Expression.Quote(resultsSelectorLambda)
);
But I can't figure out how to write rest of query using this syntax.
Does anyone can help me?
I would follow an approach to achieve that:
Get the Expression equivalent of the LINQ query.
Get the ToString() of the Expression extracted from the LINQ query.
Study the Expression, to understand the input parameters, type parameters, Expression Arguments etc...
Get back to me if the approach mentioned is not clear.
I just copied + pasted the "join" implementation in dynamic.cs and made couple of changes to make "GroupJoin" to work.
public static IQueryable GroupJoin(this IQueryable outer, IEnumerable inner, string outerSelector, string innerSelector, string resultsSelector, params object[] values)
{
if (inner == null) throw new ArgumentNullException("inner");
if (outerSelector == null) throw new ArgumentNullException("outerSelector");
if (innerSelector == null) throw new ArgumentNullException("innerSelector");
if (resultsSelector == null) throw new ArgumentNullException("resultsSelctor");
LambdaExpression outerSelectorLambda = DynamicExpression.ParseLambda(outer.ElementType, null, outerSelector, values);
LambdaExpression innerSelectorLambda = DynamicExpression.ParseLambda(inner.AsQueryable().ElementType, null, innerSelector, values);
Type resultType = typeof(IEnumerable<>).MakeGenericType(inner.AsQueryable().ElementType);
ParameterExpression[] parameters = new ParameterExpression[]
{
Expression.Parameter(outer.ElementType, "outer"), Expression.Parameter(resultType, "inner")
};
LambdaExpression resultsSelectorLambda = DynamicExpression.ParseLambda(parameters, null, resultsSelector, values);
return outer.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "GroupJoin",
new Type[] { outer.ElementType, inner.AsQueryable().ElementType, outerSelectorLambda.Body.Type, resultsSelectorLambda.Body.Type },
outer.Expression, inner.AsQueryable().Expression, Expression.Quote(outerSelectorLambda), Expression.Quote(innerSelectorLambda), Expression.Quote(resultsSelectorLambda)));
}

Resources