Use LINQ to select elements within a generic list and casting to their specific type - linq

I have a base class, called NodeUpgrade, which have several child types. An example of a specific child class is FactoryUpgrade.
I have a list of NodeUpgrades, which can be a mix of different child types. How do I write a linq query to retrieve a type of NodeUpgrade and cast to that specific type?
My working query looks something like this:
var allFactories = (from Node n in assets.Nodes
from FactoryUpgrade u in n.NodeUpgrades
where u.ClassID == NodeUpgradeTypes.Factory
select u)
This, of course, doesn't work. Can I specify the final type of the output?

If you are sure that every type in a sequence is a given type, you can use the Cast<T>() extension method. If there can be multiple types in the list and you only want one of them, you can use OfType<T>() to filter the sequence.
List<Animal> animals = ...
// assumes all animals are cats
var cats = animals.Cast<Cat>();
// var cats = (from animal in animals where ... select animal).Cast<Cat>();
// or maybe animals can contain dogs, but you don't want them
var cats = animals.OfType<Cat>();
The difference is that Cast will throw an exception if an animal isn't a cat, whereas OfType will perform a type check before actually trying the conversion. I would favor Cast over OfType when you are confident of the uniform type. (Also note that these do not perform user-defined conversions. If you have defined an implicit or explicit conversion, those will not be supported by these methods.)
The resulting sequence in each case will be IEnumerable<Cat>, which you can do further query operations on (filters, groupings, projections, ToList(), etc.)

You can use the method OfType<>
var allFactories = (from Node n in assets.Nodes
from FactoryUpgrade in n.NodeUpgrades
where u.ClassID == NodeUpgradeTypes.Factory
select u).OfType<ChildType>();

As others have said, use the .OfType extension method to filter the types (assuming you have set the inheritance model and appropriate discriminators on your data source). This will translate in the database to include the appropriate Where clause on the discriminator (ClassID).
var allFactories = from n in assets.Nodes
from u in n.NodeUpgrades.OfType<FactoryUpgrade>()
select u;
You didn't specify here if you were using EF, LINQ to SQL, or just Linq to Objects in this case. Each has a different way of modeling the inheritance. If you need help with the modeling portion, let us know which OR/M you are using.

Related

Realm Xamarin LINQ Select

Is there a way to restrict the "columns" returned from a Realm Xamarin LINQ query?
For example, if I have a Customer RealmObject and I want a list of all customer names, do I have to query All<Customer> and then enumerate the results to build the names list? That seems cumbersome and inefficient. I am not seeing anything in the docs. Am I missing something obvious here? Thanks!
You have to remember that Realm is an object based store. In a RDBMS like Sqlite, restricting the return results to a sub-set of "columns" of an "record" makes sense, but in an object store, you would be removing attributes from the original class and thus creating a new dynamic class to then instantiate these new classes as objects.
Thus is you want just a List of strings representing the customer names you can do this:
List<string> names = theRealm.All<Customer>().ToList().Select(customer => customer.Name).ToList();
Note: That you take the Realm.All<> results to a List first and then using a Linq Select "filter" just the property that you want. Using a .Select directly on a RealmResults is not currently supported (v0.80.0).
If you need to return a complex type that is a subset of attributes from the original RealObject, assuming you have a matching POCO, you can use:
var custNames = theRealm.All<Customer>().ToList().Select((Customer c) => new Name() { firstName = c.firstName, lastName = c.lastName } );
Remember, once you convert a RealmResult to a static list of POCOs you do lose the liveliness of using RealmObjects.
Personally I avoid doing this whenever possible as Realm is so fast that using a RealmResult and thus the RealObjects directly is more efficient on processing time and memory overhead then converting those to POCOs everytime you need to new list...

update a property value during linq to sql select (involves join)

Ok I have seen many questions that based on their text could be something like this but not quite. Say I have something like this
(from r in reports
join u in SECSqlClient.DataContext.GetTable<UserEntity>()
on r.StateUpdateReportUserID equals u.lngUserID
select r).
If reports have a bunch of say reportDTO class and I want to select from a list of that DTO but at the same time set one property to a property in userEntity how would I do that? Basically I want all other fields on the report maintained but set a user name from the user table. (There is a reason this is not done in one big query that gets a list of reports)
What I am looking for is something like Select r).Something(SOME LAMBDA TO SET ONE FIELD TO userEntity property).
There is a dirty way to do this, which is
var repQuery = from r in reports ... select new { r, u };
var reps = repQuery.Select(x => { x.r.Property1 = x.u.Property1; return x.r; };
However, When it comes to functional programming (which Linq is, arguably) I like to adhere to its principles, one of which to prevent side effects in functions. A side effect is a change in state outside the function body, in this case the property value.
On the other hand, this is a valid requirement, so I would either use the ForEach method after converting the query to list (ToList()). Foreach is expected to incur side effects. Or I would write a clearly named extension method on IEnumerable<T> (e.g. DoForAll) that does the same, but in a deferred way. See Why there is no ForEach extension method on IEnumerable?.

Can LINQ ToArray return a strongly-typed array in this example?

I've contrived this example because it's an easily digested version of the actual problem I'm trying to solve. Here are the classes and their relationships.
First we have a Country class that contains a Dictionary of State objects indexed by a string (their name or abbreviation for example). The contents of the State class are irrelevant:
class Country
{
Dictionary<string, State> states;
}
class State { ... }
We also have a Company class which contains a Dictionary of zero or more BranchOffice objects also indexed by state names or abbreviations.
class Company
{
Dictionary<string, BranchOffice> branches;
}
class BranchOffice { ... }
The instances we're working with are one Country object and an array of Company objects:
Country usa;
Company companies[];
What I want is an array of the State objects which contain a branch. The LINQ I wrote is below. First it grabs all the companies which actually contain a branch, then joins to the list of states by comparing the keys of both lists.
The problem is that ToArray returns an anonymous type. I understand why anonymous types can't be cast to strong types. I'm trying to figure out whether I could change something to get back a strongly typed array. (And I'm open to suggestions about better ways to write the LINQ overall.)
I've tried casting to BranchOffice all over the place (up front, at list2, at the final select, and other less-likely candidates).
BranchOffice[] offices =
(from cm in companies
where cm.branches.Count > 0
select new {
list2 =
(from br in cm.branches
join st in usa.states on br.Key equals st.Key
select st.Value
)
}
).ToArray();
You can do:
select new MyClassOfSomeType {
..
)
For selection, you can give it a custom class type. You can also then use ToList. With ArrayList, if you need to keep it loosely typed, you can then make it strongly typed later using Cast<>, though only for any select result that doesn't generate an anonymous class.
HTH.
If i understand the problem correctly, the you want just the states that have office brances in them, not the branches too. If so, one posible linq is the following:
State[] offices =
(from cm in companies
where cm.branches.Count > 0
from br in cm.branches
join st in usa.states on br.Key equals st.Key
select st.Value
).Distinct().ToArray();
If you want both the states and the branches, then you will have to do a group by, and the result will be an IEnumerable>, which you can process after.
var statesAndBranches =
from cm in companies
where cm.branches.Count > 0
from br in cm.branches
join st in usa.states on br.Key equals st.Key
group br.Value by st.Value into g
select g;
Just one more thing, even though you have countries and branches declared as dictionaries, they are used as IEnumerable (from keyValuePair in dictionary) so you will not get any perf benefit form them.

DynamicObject LINQ query does't works with custom class!

DynamicObject LINQ query with the List compiles fine:
List<string> list = new List<string>();
var query = (from dynamic d in list where d.FirstName == "John" select d);
With our own custom class that we use for the "usual" LINQ compiler reports the error "An expression tree may not contain a dynamic
operation":
DBclass db = new DBclass();
var query = (from dynamic d in db where d.FirstName == "John" select d);
What shall we add to handle DynamicObject LINQ?
Does DBClass implement IEnumerable? Perhaps there is a method on it you should be calling to return an IEnumerable collection?
You could add a type, against which to write the query.
I believe your problem is, that in the first expression, where you are using the List<>, everything is done in memory using IEnumerable & Link-to-Objects.
Apparently, your DBClass is an IQueryable using Linq-to-SQL. IQueryables use an expression tree to build an SQL statement to send to the database.
In other words, despite looking much alike, the two statements are doing radically different things, one of which is allowed & one which isn't. (Much in the way var y = x * 5; will either succeed or fail depending on if x is an int or a string).
Further, your first example may compile, but as far as I can tell, it will fail when you run it. That's not a particular good benchmark for success.
The only way I see this working is if the query using dynamic is made on IEnumerables using Link-to-Objects. (Load the full table into a List, and then query on the list)

Return Datatype of Linq Query Result

I think I'm missing something really basic.
var signatures=from person in db.People
where person.Active==true
select new{person.ID, person.Lname, person.Fname};
This linq query works, but I have no idea how to return the results as a public method of a class.
Examples always seem to show returning the whole entity (like IQueryable<People>), but in this case I only want to return a subset as SomeKindOfList<int, string, string>. Since I can't use var, what do I use?
Thanks!
You can get concrete types out of a linq query, but in your case you are constructing anonymous types by using
select new{person.ID, person.Lname, person.Fname};
If instead, you coded a class called "Person", and did this:
select new Person(peson.ID, person.Lname, person.Fname);
Your linq result (signatures) can be of type IEnumerable<Person>, and that is a type that you can return from your function.
Example:
IEnumerable<Person> signatures = from person in db.People
where person.Active==true
select new Person(person.ID, person.Lname, person.Fname);

Resources