LINQ where query on collection of different derived classes - linq

I have a collection of different objects that derive from the same parent.
How can I extract objects of a particular type from a collection containing mixed types
e.g.
public class A {}
public class B : A {}
public class C : A {}
The collection will contain objects of type B and C
I'm halfway there just need help filling in the '[]' bit
var x = from xTypes in xCollection where '[type of object is type B]' select xTypes;
Thanks.

You should use the OfType<T> extension method rather than LINQ query syntax for this:
var x = xCollection.OfType<B>();
This will give you back an IEnumerable<B>. If you do want to use the LINQ query syntax, you'd have to do this:
var x = from obj in xCollection where obj is B select (B)obj;

var x = from xTypes in xCollection
where xTypes is B
select xTypes;
or if you want exactly this type and not any derived types:
var x = from xTypes in xCollection
where xTypes.GetType() == typeof(B)
select xTypes;

Related

Avoid "Parameterless Queries Error" with Linq Let clause

I'd like my Linq query to create an additional column in the results on the fly. In this case the column is a Class object I created that will contain image info. I was wondering what the right way is of doing this:
var validPics = (from x in db.picsVotesTagsJs let picObj = new CarShowImages(x.picname) where x.enabled == 1 select x).Take(25);
var myArray = validPicSummaries.ToArray();
Line 2 gerenates the error:
Only parameterless constructors and initializers are supported in LINQ to Entities.
This is my first time using the Let clause. My queries are usually pretty simple.
Create parameterless constructor and use some public property (e.g. PicName) to set picture name to your CarShowImages object:
var validPics = (from x in db.picsVotesTagsJs
where x.enabled == 1
select new CarShowImages { PicName = x.picname }).Take(25);
var myArray = validPics.ToArray();

Linq with DynamicObject

I have List where MyType : DynamicObject. The reason for MyType inheriting from DynamicObject, is that I need a type that can contain unknown number of properties.
It all works fine until I need to filter List. Is there a way I can do a linq that will do something like this:
return all items where any of the properties is empty string or white space?
(from the comment) can I do above linq query with List?
Yes, here is how you can do it with ExpandoObject:
var list = new List<ExpandoObject>();
dynamic e1 = new ExpandoObject();
e1.a = null;
e1.b = "";
dynamic e2 = new ExpandoObject();
e2.x = "xxx";
e2.y = 123;
list.Add(e1);
list.Add(e2);
var res = list.Where(
item => item.Any(p => p.Value == null || (p.Value is string && string.IsNullOrEmpty((string)p.Value)))
);
The ExpandoObject presents an interface that lets you enumerate its property-value pairs as if they were in a dictionary, making the process of checking them a lot simpler.
Well as long as each object's properties are not unknown internally to themselves you could do it.
There isn't a great generic way to test all the properties of a dynamic object, if you don't have control over the DynamicObject you hope the implementer implemented GetDynamicMemberNames() and you can use the nuget package ImpromptuInterface's methods for getting the property names and dynamically invoking those names.
return allItems.Where(x=> Impromptu.GetMemberNames(x, dynamicOnly:true)
.Any(y=>String.IsNullOrWhiteSpace(Impromptu.InvokeGet(x,y));
Otherwise, since it's your own type MyType you can add your own method that can see internal accounting for those member values.
return allItems.Where(x => x.MyValues.Any(y=>String.IsNullOrWhitespace(x));

Query a for a specific object type in a collection

If you have two objects, ObjectA and ObjectB both inheriting from AbstractObject and a collection of AbstractObject. What would a linq statement look like where I select all objects in the collection of specific type. ex. something like:
var allBs = from b in collection where type == ObjectB select b;
You can use Enumerable.OfType:
var allBs = collection.OfType<ObjectB>();
This gives you all elements where the type is castable to ObjectB. If you want objects which are only of type of ObjectB:
var allBs = collection.Select(i => i.GetType() == typeof(ObjectB));
or, alternatively:
var allBs = from b in collection
where b.GetType() == typeof(ObjectB)
select b;
Very simple:
IEnumerable<ObjectB> allBs = collection.OfType<ObjectB>();
Or:
IEnumerable<AbstractObject> allBy = from b in collection
where b is ObjectB
select b;
The second query retains the same enumerable type as the collection, the first implicitly casts to IEnumerable<ObjectB>.
You could use these alternatives to cast the second query to IEnumerable<ObjectB>.
IEnumerable<ObjectB> allBs = (from b in collection
where b is ObjectB
select b).Cast<ObjectB>();
IEnumerable<ObjectB> allBs = from b in collection
where b is ObjectB
select b as ObjectB;

Struggling with .ToList() returing an EntitySet<...>, not an IList<..>

I'm trying to retrieve a list of Id's from a collection that is a few levels deep in an object heirachy. When i try to do a ToList(), I keep getting an EntityList<> retrieved instead .. which means it's not allowing me to retrieve an instance's BarId property because the EntitySet is a Enumerable, not a single instance object.
Foo.Child1 (1 to 1)
Child1.Children2 (0 to many of type Bar)
Bar.BarId int;
IList<Foo> fooList = (from blah blah blah).ToList();
var children2List = (from x in fooList
select x.Child1.Children2).ToList();
It keeps returning children2List as an EntitySet<Bar>, not an IList<Bar>. As such, i'm struggling to retrieve the list of BarId's from children2List.
please help!
Your can use:
var children2List = fooList.SelectMany( x => x.Child1.Children2 ).ToList();
This will allow you to do something like:
children2List.ForEach( b => b.BarId.Print() );
In your query, you turn the whole result into a list, not the individual Children2 sets.
Try
var children2List = (from x in fooList
select x.Child1.Children2.ToList()).ToList();
This will turn each Children2 into a List.
EntitySet<T> implements IList<T>, so you already are returning IList<Bar>.

Building Dynamic LINQ Queries based on Combobox Value

I have a combo box in Silverlight. It has a collection of values built out of the properties of one of my LINQ-to-SQL objects (ie Name, Address, Age, etc...). I would like to filter my results based off the value selected in a combo box.
Example: Say I want everyone with a last name "Smith". I'd select 'Last Name' from the drop down list and enter smith into a textbox control. Normally I would write a LINQ query similar to...
var query = from p in collection where p.LastName == textbox.Text select p;
Is it possible to decide the property dynamically, maybe using Reflection? Something like
var query = from p in collection where p.(DropDownValue) == textbox.Text select p;
Assuming:
public class Person
{
public string LastName { get; set; }
}
IQueryable<Person> collection;
your query:
var query =
from p in collection
where p.LastName == textBox.Text
select p;
means the same as:
var query = collection.Where(p => p.LastName == textBox.Text);
which the compiler translates from an extension method to:
var query = Queryable.Where(collection, p => p.LastName == textBox.Text);
The second parameter of Queryable.Where is an Expression<Func<Person, bool>>. The compiler understands the Expression<> type and generates code to build an expression tree representing the lambda:
using System.Linq.Expressions;
var query = Queryable.Where(
collection,
Expression.Lambda<Func<Person, bool>>(
Expression.Equal(
Expression.MakeMemberAccess(
Expression.Parameter(typeof(Person), "p"),
typeof(Person).GetProperty("LastName")),
Expression.MakeMemberAccess(
Expression.Constant(textBox),
typeof(TextBox).GetProperty("Text"))),
Expression.Parameter(typeof(Person), "p"));
That is what the query syntax means.
You are free to call these methods yourself. To change the compared property, replace this:
typeof(Person).GetProperty("LastName")
with:
typeof(Person).GetProperty(dropDown.SelectedValue);
Scott Guthrie has a short series on dyamically built LINQ to SQL queries:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
That's the easy way...then there's another way that's a bit more involved:
http://www.albahari.com/nutshell/predicatebuilder.aspx
You can also use the library I created: http://tomasp.net/blog/dynamic-linq-queries.aspx. You would store the properties in ComboBox as lambda expressions and then just write:
var f = (Expression<Func<Product, string>>)comboBox.SelectedValue;
var query =
from p in collection
where f.Expand(textBox.Text)
select p;

Resources