I have a collection of type objects which I know they are type Employee. I'd like to perform some linq operations on them using the employee some thing similar to this:
var options = (from e in m_Employees
select (e as Employee).DepartmentCode).Distinct();
But the as employee is not surprisingly giving an error. is there a way around it?
Changing the collection is not really an options since I,m maintaining the code and I want to avoid big changes.
You can use either
from e in m_Employees.Cast<Employee>()
select e.DepartmentCode
or
from e in m_Employees.OfType<Employee>()
select e.DepartmentCode
Cast thows an error if you can not cast each item to Employee, but OfType will filter out those objects not matching the type.
Rather than using as Employee it would be better to make the compiler basically insert a call to Cast<T> using an explicitly typed range variable:
var options = (from Employee e in m_Employees
select e.DepartmentCode).Distinct();
Or alternatively and equivalently:
var options = m_Employees.Cast<Employee>()
.Select(e => e.DepartmentCode)
.Disinct();
However, I still wouldn't have expected your original code to fail, if the array really does only include Employee references... If you were getting a NullReferenceException then either one of the values was null, or it was a non-null reference to a non-Employee object. These will both still give you an error with the above code, but you'll be able to see which one based on whether you still get a NullReferenceException or an InvalidCastException.
In general you should only use as when you're going to use the result conditionally. If you're sure that every value is really of the right type, you should use a cast instead - so that if you're wrong, you'll get the code blowing up with an exception instead of propagating a null reference to the rest of the code, where it could cause harm later on and make it hard to spot the source of the error.
If you were getting a compile-time error then there are a number of possible causes, based on what exception you were seeing.
EDIT: Okay, so it was an IEnumerable causing a compile-time error... Cast<T>() and OfType<T>() are both extension methods on just IEnumerable instead of on IEnumerable<T>.
One option would be:
(from e in m_Employees
let x = e as Employee
select x.DepartmentCode).Distinct();
Use this:
var options = (from e in m_Employees.Cast<Employee>()
select e.DepartmentCode).Distinct();
The important part is the Cast<Employee>. My answer assumes that m_Employees is an IEnumerable like ArrayList instead of an IEnumerable<Employee> like List<Employee>.
You could try this:
var options = m_Employees
.Cast<Employee>()
.Select(item => item.DepartmentCode)
.Distinct();
Related
I am trying to achieve a simple task, and I don't find a way to do it. I am trying to convert a LINQ result to a list of objects. I am following the syntax posted in this accepted SO answer.. Here is my code:
var LinqHallazgos = (from RA_Hallazgos in context.RA_Hallazgos
select new
{
HallazgoId = RA_Hallazgos.HallazgoId,
Hallazgo = RA_Hallazgos.Hallazgo
});
List<RA_Hallazgos> Hallazgos = LinqHallazgos.ToList<RA_Hallazgos>();
And this is the error that I get:
It says that "LinqHallazgos", which is an iqueryable, doesn't contain a definition for ToList. But I see the "ToList" method in intellisense. It also says that it expect an IEnumerable but this answer seems to use similar syntax.
What I am doing wrong and how in the world I get the LINQ result as a list of a particular object??
You are making this too complex. It seems all you want to do is materialize the DbSet<RA_Hallazgos> to memory (retrieve the content from the database). If that is the case just use the ToList() linq extension on the DbSet and you are done. Note that it will retrieve everything as you did not specify a filter (ie. any limiting predicates like Where / Take / Skip / etc).
List<RA_Hallazgos> Hallazgos = context.RA_Hallazgos.ToList();
Just call .ToList(). You have an anonymous type there (the new {}) so you can't specify the type explicitly even if you wanted to.
Otherwise, if RA_Hallazgos is an actual type, use new RA_Hallazgos{} to avoid creating an anonymous type.
Try
select new RA_Hallazgos
{
HallazgoId = RA_Hallazgos.HallazgoId,
Hallazgo = RA_Hallazgos.Hallazgo
}
List<RA_Hallazgos> Hallazgos = LinqHallazgos.ToList()();
I like to think of myself as pretty good with LINQ, but every now and then I try to accomplish something that I just can't get to work. I'd like to convert a SPListItemCollection to a dictionary so I can use the key to look up a value without the need for a LINQ query each time:
var formsConfigItems = new Dictionary<string, string>();
foreach (SPListItem item in list.GetItems(query))
formsConfigItems.Add(item.Title, (item["Value"] == null ? string.Empty : item["Value"].ToString()));
This works, but I was hoping to do it in a cleaner fashion, using LINQ. (not a big deal but I like to use LINQ over for-loops whenever possible, although it's the same thing behind the scenes.
I tried to do something like this:
var formsConfigItems = (from SPListItem i in list.GetItems(query)
select new { i.Title, i["Value"].ToString() }).ToDictionary<string, string>(k=>k.Key, k=>k.Value);
But that doesn't seem to work. If I try to use a lambda expression on list.GetItems(query), I'm not given the option to use .Where or any LINQ commands (which is weird because it is an SPListCollection)
Thanks in advance.
Try:
var formsConfigItems = list.GetItems(query)
.Cast<SPListItem>()
.ToDictionary(item => item.Title,
item => Convert.ToString(item["Value"]));
To answer your queries:
If I try to use a lambda expression on list.GetItems(query), I'm not
given the option to use .Where or any linq commands (which is weird
because it is an SPListCollection)
That's because SPListCollection is an "old-school" collection that implements IEnumerable but not IEnumerable<T>, so C# / LINQ (at compile-time anyway) can't tell what type of items it contains. The Cast<SPListItem>() call helps work around this issue - it turns an IEnumerable into an IEnumerable<T>, allowing the type-algebra to work out at compile-time . Your for loop doesn't have this issue since you explicitly specify the type of the loop variable - the compiler inserts a cast on your behalf for each item in the sequence.
I tried to do something like this (query expression). But that
doesn't seem to work.
That's because you are not constructing the anonymous type instance correctly (property names can't be inferred for arbitrary expressions) and your lambda expression isn't quite right either (the property names you use don't match the property names of the anonymous type). Try this instead:
var formsConfigItems = (from SPListItem i in list.GetItems(query)
select new
{
i.Title,
Value = Convert.ToString(i["Value"])
}).ToDictionary(a => a.Title, a => a.Value);
Ani's got the better solution IMO, but one other thing you're missing: Your LINQ statement is creating a collection of anonymous items, but you're not giving names to the properties in that anonymous class.
The k=>k.Key expression doesn't work, because it doesn't know what Key is - you've only defined Title (since you didn't give it a name, it borrowed the one from the object). The Value one can't be automatically figured out, so it would throw a compiler error.
To do it this way, you'd need to specifically declare the names:
new { Key = i.Title, Value = i["Value"].ToString() }
How do I remove an object directly from an IGrouping IGrouping<DateTime, VMAppointment>?
The only way I know of currently is to generate a new IGrouping without the concering element, but I don't like this way because it causes some trouble within my application.
Any ideas?
No, there's no way to mutate an IGrouping<,>, at least in general - and even if you knew the concrete type, I don't believe any of the implementations exposed by the .NET framework allow the group to be mutated.
Presumably the grouping is the result of some query - so if possible, change the original query to exclude the values you aren't interested in.
I know this is old question, but hopefully this helps someone else. A workaround for this is to cast the group to a list, then use the values from the list instead of the group.
var groups = someList.GroupBy(x => x...);
foreach (var group in groups)
{
var groupList = group.ToList();
...
groupList.Remove(someItem);
//Process the other code from groupList.
}
You could cast using Select and use TakeWhile if you have a testable condition (such as null as in the example) on a property in your group:
var removedItemsList = group.Select(x => x.TakeWhile(t => t.someProperty != null));
This will return an IEnumerable<IEnumerable<YourGroup>>.
I am using Linq to entity and have the following query
IQueryable<DomainModel.User> userResult =
userResult.OrderBy(u => u.UserClientRoles.OrderBy(r => r.Role.RoleName));
But I am getting this error
DbSortClause expressions must have a type that is order comparable
parameter Name :Key
and it returns an empty collection.
Any idea what's going on?
.OrderBy(), when working with databases, is supposed to take in a delegate that returns only a single property that represents a column in your database. I'm not sure what you're trying to do, but it looks like
u.UserClientRoles.OrderBy(r => r.Role.RoleName)
Will return an enumeration of values, which can't be ordered.
I had the same problem, I solved it using this:
your code:
IQueryable<DomainModel.User> userResult = userResult.OrderBy(u => u.UserClientRoles.OrderBy(r => r.Role.RoleName));
my code:
List<Membership> results = new List<Membership>();
results.AddRange(memberships.OrderBy(m => m.Roles));
memberships = results.AsQueryable();
coincidences:
*.OrderBy(m => m.Roles)
solution:
*.OrderBy(m => m.Roles.Select(r => r.RoleId).FirstOrDefault())
possible problem's reason:
Maybe, you did what I did, and cause that 1 user/member could have more than 1 role in the same membership. That made a conflict with/to OrderBy() because the application can just "order" a single element at the time, when she call the Role (which is an ICollection of elements) the instead receive more than 1 element with no kind of priority's levels (even when we could assume that the application will take the role's index as priority's base level, actually its don't).
solution's explaination:
When you add the *.Select(r => r.RoleId), you are specifying to the application which element will be used to OrderBy(). But, as you shall see when you maybe reached at this point, just by using the *.Select(r => r.RoleId) could be not enough, because the application is still receiving multiple results with the same priority's level. Adding *.Select(r => r.RoleId).FirstOrDefault() you are basically saying: "...I don't care how many results you received from that element, just the focus on the first result, or order them by its default..." (default normally means EMPTY or NULL).
additional information:
I used non-official's simple concepts/meanings to explain a complex solution with simple words, which means that you could maybe have problems to find similar posts in the web by using the words/concepts used in this "answer". Otherwise, the code itself works and you shouldn't not have any problem by applying it and/or modifying it by yourself. GOOD LUCK!!! (^_^)
In my case, I was accidentally trying to order by an object instead of ordering by one of it's properties.
You should you use
var query = from Foo in Bar
orderby Foo.PropertyName
select Foo;
Instead of
var query = from Foo in Bar
orderby Foo
select Foo;
Note: you will get the same behaviour event if there is an override on Foo's ToString() method.
Think this is a very basic question, but it's my first LINQ query and I'm completely stuck:
I have a dictionary with string key and list value (see definition below) and want to pull out elements of a list of a particular type having selected the list by the dictionary key.
IDictionary<string, IList<MyBaseType>> dataItemMap;
Where MySubType extends MyBaseType.
My dodgy query is:
string identCode = "foo";
IEnumerable<MySubType> query =
from entry in dataItemMap
where entry.Key == identCode
select entry.Value.OfType<MySubType>();
And the error message (from LinqPad):
Cannot implicitly convert type
'System.Collections.Generic.IEnumerable<System.Collections.Generic.IEnumerable<MySubType>>'
to 'System.Collections.Generic.IEnumerable<MySubType>'.
An explicit conversion exists (are you missing a cast?)
The problem is clearly in the entry.Value.OfType<> but how can I specify the lists elements? I'm looking for something like entry.Value.Items.OfType<> ?
thanks.
I think you want something like this:
IEnumberable<MySubType> query = dataItemMap[identCode].OfType<MySubType>();
This will get the list with the given key, and then filter it to return only MySubType elements.
EDIT: I've been focusing on why the existing solution didn't work (and the general problem of "I've got a list of values for each element, and I want to flatten it") rather than taking a step back. As Andy's answer shows, you should almost certainly use the fact that it's a dictionary - turning it from an O(n) operation to O(1) :)
Two caveats:
Your current code will always perform an ordinal, culture-insensitive comparison with identCode and the dictionary keys; using the dictionary lookup will use whatever comparer it was constructed with.
Your current code will return an empty sequence if identCode isn't found in the dictionary; the dictionary indexer will throw an exception. You can use TryGetValue if you want to avoid that.
Note that if you know that all the elements in the last you're picking are actually of the right type, it would probably be better to use Cast than OfType:
var query = dataItemMap[identCode].Cast<MySubType>();
I generally prefer Cast to OfType when both would work, as it means that if my assumptions about the data in the sequence prove incorrect, I find out about it with an exception rather than silently missing data.
Note that Cast will also return null elements, whereas OfType won't.
No, the problem isn't in using OfType<> - it's that you've ended up with a sequence of sequences, but you're trying to assign that to a single sequence.
Either change the return type, or use another from clause to flatten the results:
IEnumerable<MySubType> query = from entry in dataItemMap
where entry.Key == identCode
from value in entry.Value.OfType<MySubType>()
select value;
I'd be tempted to use the extension methods directly:
var query = dataItemMap.Where(e => e.Key == identCode)
.SelectMany(e => e.Value.OfType<MySubType>());