Linq query referencing objects and a string array - c#

I am having some trouble in converting the following code to use LINQ.
int occurs = 0;
foreach (string j in items)
{
if (!string.IsNullOrEmpty(j))
{
WorkflowModule tempWM = new WorkflowModule(j);
if (tempWM.StateID == item.StateID)
{
occurs++;
}
}
}
return occurs;
So far, I have:-
var lstItems = (from lstItem in items
where !string.IsNullOrEmpty(lstItem)
let objWorkflowModule = new WorkflowModule(lstItem)
select new
{
tempWM = objWorkflowModule.StateID
}).Where(item.StateID == tempWM));
return lstItems.Count();
but intellisense is not liking the line '.Where(item.StateID == tempWM))'
Can anyone help me achieve this?
Thanks.

When you use the method syntax, you need to use a lambda on the Where operator:
...
}).Where(x => x.tempWM == item.StateID));
In other words, you need to "declare" the variable x which holds the result of the previous part of the query.

It doesn't look like item is initialized anywhere in your statement.

Here's how I'd do this
var lstItems = from lstItem in items
where !string.IsNullOrEmpty(lstItem)
let objWorkflowModule = new WorkflowModule(lstItem)
select objWorkflowModule.StateID;
return lstItems.Count(t=> t == item.StateID);
I'm assuming item is a variable defined outside of the original code you submitted. Basically you don't need to create the anonymous class in the query and you can put the predicate in you're Where into Count instead. But as others have said the main issue is that you need to express your predicate as a lambda.

Related

Runtime Sorting and Types with Linq

I have seen numerous articles which all seem to nibble around the issue I am having but none have provided an actual resolution to the problem. Which is to say they all get me to about 98% solution only to fail in some small detail.
I have an IEnumerable that is collected at run time. This IEnumerable could be of ANYTHING. I will not know until runtime. I need to sort it however based on a list of propertyNames and sort directions in a List of KeyValuePair objects provided as an argument.
public static void SortData(IEnumerable<dynamic> dataToSort, List<KeyValuePair<string, string>> sortArgs)
{
}
I first get the Type of the IEnumerable. I have created a method for this. I won't get into this detail here. It's been tested and does return the proper Type.
public static void SortData(IEnumerable<dynamic> dataToSort, List<KeyValuePair<string, string>> sortArgs)
{
Type dataType = TypeService.GetType(data);
}
I then attempt to create an initial IOrderedEnumerable that I can apply the sortArgs sort to.
public static void SortData(IEnumerable<dynamic> dataToSort, List<KeyValuePair<string, string>> sortArgs)
{
Type dataType = TypeService.GetType(dataToSort);
// Create IOrderedEnumerable
//
var query = from dataItem in dataToSort
orderby // ?????
select dataItem;
// apply sortArgs to IOrderedEnumerable
//
for(int argIDX = 0; argIDX < sortArgs.Count; argIDX++)
{
var arg = sortArgs[argIDX];
var sortField = arg.Key.Trim();
var sortDirection = arg.Value.Trim().ToUpper();
if(argIDX == 0)
{
if(sortDirection == "DESC")
{
query = query.OrderByDescending(e => e.GetType().GetProperty(sortField).GetValue(e));
}
else
{
query = query.OrderBy(e => e.GetType().GetProperty(sortField).GetValue(e));
}
}
else
{
if(sortDirection == "DESC")
{
query = query.ThenByDescending(e => e.GetType().GetProperty(sortField).GetValue(e));
}
else
{
query = query.ThenBy(e => e.GetType().GetProperty(sortField).GetValue(e));
}
}
}
// After applying the sort retreive the contents
//
dataToSort = query.ToList();
}
It seems by this point I have all the information I should need to sort the original dataToSort argument. But defining a property to initialize the IOrderedEnumerable is eluding me.
I have tried a number of different techniques I have read about ...
var query = from dataItem in dataToSort
orderby ( X => 1) //ERR: The type of one of the expressions in the OrderBy clause is incorrect. Type inference failed in the call to 'OrderBy'.
select dataItem;
I have tried to create a new Typed list (since I know the type) so that the expressions in the OrderBy clause could be inferred more accurately.
var typedDataToSort = new List<dataType>(); //ERR: dataType is a variable used like a type
foreach(var item in dataToSort)
{
typedDataToSort.Add( item );
}
I have tried to get the PropertyInfo for a property to sort on..
PropertyInfo propInfo = dataType.GetProperty(dataValueField);
var query = from dataItem in dataToSort
orderby (x => propInfo.GetValue(x, null)) //ERR: The type of one of the expressions in the OrderBy clause is incorrect. Type inference failed in the call to 'OrderBy'. Of couse this could not work since `dataType` is an INSTANCE of
select dataItem;
I have just run out of ideas.
To create an IOrderedIEnumerable from a List<T> without manipulating the order you can just execute a noop sort by doing something like this:
var myList = new List<String>(){"test1", "test3", "test2"}
IOrderedIEnumerable<String> query = myList.OrderBy(x => 1);
The same goes for an IEnumerable - however you must ensure that the underlaying type of IEnumerable provides stable order for each iteration.

Linq Query to check if the records are all the same

I am very much new to the Linq queries. I have the set of records in the csv which is like below
ProdID,Name,Color,Availability
P01,Product1,Red,Yes
P02,Product2,Blue,Yes
P03,Product1,Yellow,No
P01,Product1,Red,Yes
P04,Product1,Black,Yes
I need to check for the Names of the each product and if its is not the same in all the records then I need to send an error message.I know the below query is used to find the duplicates in the records but not sure how can I modify it check if it all has the same values.
ProductsList.GroupBy(p => p.Name).Where(p => p.Count() > 1).SelectMany(x => x);
var first = myObjects.First();
bool allSame = myObjects.All(x=>x.Name == first.Name);
Enumerable.All() will return true if the lambda returns true for all elements of the collection. In this case we're checking that every object's Name property is equal to the first (and thus that they're all equal to each other; the transitive property is great, innit?). You can one-line this by inlining myObjects.First() but this will slow performance as First() will execute once for each object in the collection. You can also theoretically Skip() the first element as we know it's equal to itself.
if I understand correctly you want to check if product exists in the list
using System.Linq;
private bool ItemExists(string nameOfProduct) {
return ProductsList.Any(p=> p.Name== nameOfProduct);
}
UPD after author comment:
To know all the records that are not having the same name as the first record:
var firstName = ProductsList[0].Name;
var differentNames = ProductsList.Where(p => p.Name != firstName);
Another option (just to have all other names): ProductsList.Select(p => p.Name).Where(n => n != firstName).Distinct()
Old version
So, if there are at least two different names then you should return an error?
LINQ way: return ProductsList.Select(p => p.Name).Distinct().Count() <= 1
More optimizied way:
if (ProductsList.Count == 0)
return true;
var name = ProductsList[0].Name;
for (var i = 1; i < ProductsList.Count; i++)
{
if (ProductsList[i].Name != name)
return false;
}
return true;

New to programming how to make this code more concise

Hi this is my first question so apologies if it is really basic - I am very new to programming!!!
Using c# in MVC I am trying to select object which has a Date property from entitymodel context. This date then selects the relevant Weight object and so on to get my list of "Set" objects.
The code works and does what I want but would like some general guidance on how to make this code more concise. Here is the code:
public ActionResult showDiary(string datein)
{
LocalTestEntities1 dblists = new LocalTestEntities1();
DateTime date = Convert.ToDateTime(datein);
IEnumerable<ExerciseDiary> diary = from o in dblists.ExerciseDiaries where o.Date == date select o;
var mydiary = diary.ToList();
ExerciseDiary thediary = mydiary[0];
IQueryable<Weight> weights = from o in dblists.Weights where o.DiaryID == thediary.ID select o;
var selectedWeight = weights.ToList();
Weight weight = selectedWeight[0];
IEnumerable<Set> sets = from x in dblists.Sets where x.WeightId == weight.WeightID select x;
return View(sets);
}
It seems that I am taking too many steps here. I know that I am only returning one object to diary. Is there a way to get this object from dblists without sending to an IEnumerable?
Using the First() method will make things a little more concise:
public ActionResult showDiary(string datein)
{
using (LocalTestEntities1 dblists = new LocalTestEntities1())
{
DateTime date = Convert.ToDateTime(datein);
var thediary = (from o in dblists.ExerciseDiaries
where o.Date == date
select o).First();
var weight = (from o in dblists.Weights
where o.DiaryID == thediary.ID
select o).First();
var sets = (from x in dblists.Sets
where x.WeightId == weight.WeightID
select x).ToList();
}
return View(sets);
}
You should also wrap your LINQ to Entities data access in a using block so it's properly disposed of.
There's always many ways to do things, but... I think the easiest way would be to use First() since you are always just grabbing the first result in a list.
Another way to make it a little cleaner is to put your LINQ statements on multiple lines like I did for sets.
You can also use var, which some people like and others don't to have the compiler infer the type. I did this with sets below. I feel it cleans up the code a bit when you have large declarations with IEnumerable and generics.
public ActionResult showDiary(string datein)
{
LocalTestEntities1 dblists = new LocalTestEntities1();
DateTime date = Convert.ToDateTime(datein);
ExerciseDiary thediary = dblists.ExerciseDiaries.First(o => o.Date == date);
Weight weight = dblists.Weights.First(o.DiaryID == thediary.ID);
var sets = from x in dblists.Sets
where x.WeightId == weight.WeightID
select x;
return View(sets);
}
IMO this is easier to read than what you had in your answer above.
Be careful using First() because it will throw an exception if there are no records.
public ActionResult showDiary(string datein)
{
using( var dblists = new LocalTestEntities1())
{
var date = Convert.ToDateTime(datein);
var thediary = dblists.ExerciseDiaries.First(o => o.Date == date);
var weight = dblists.Weights.First(o => o.DiaryID ==thediary.ID);
var sets = dblists.Sets.Where(x => x.WeightId == weight.WeightID).AsEnumerable();
return View(sets);
}
}
Warning: If it's possible the data wont always be there. Use FirstOrDefault instead and check for null values.

Foreach loop problem for IQueryable object

Can we use foreach loop for IQueryable object?
I'd like to do something as follow:
query = IQueryable<Myclass> = objDataContext.Myclass; // objDataContext is an object of LINQ datacontext class
int[] arr1 = new int[] { 3, 4, 5 };
foreach (int i in arr1)
{
query = query.Where(q => (q.f_id1 == i || q.f_id2 == i || q.f_id3 == i));
}
I get a wrong output as each time value of i is changed.
The problem you're facing is deferred execution, you should be able to find a lot of information on this but basically none of the code s being executed until you actually try to read data from the IQueryable (Convert it to an IEnumerable or a List or other similar operations). This means that this all happens after the foreach is finished when i is set to the final value.
If I recall correctly one thing you can do is initialize a new variable inside the for loop like this:
foreach (int i in arr1)
{
int tmp = i;
query = query.Where(q => (q.f_id1 == tmp || q.f_id2 == tmp || q.f_id3 == tmp));
}
By putting it in a new variable which is re-created each loop, the variable should not be changed before you execute the IQueryable.
You dont need a for each, try it like this:
query = objDataContext.Myclass.Where(q => (arr1.Contains(q.f_id1) || arr1.Contains(q.f_id2) || arr1.Contains(q.f_id3));
this is because "i" is not evaluated until you really use the iterate the query collectionif not by that time I believe "i" will be the last.

Modifying properties in object with LINQ and functions Lamba

Friends,
I know how to deploy and retrieve a single element in LINQ, but how can I do to change all the properties in a list. In the line below, I can only modify a record, I would modify several.
_ListaAcaoMenuInfo.Where(p => p.Id_acao == id).FirstOrDefault().Id_menu = 0;
Thanks
Use the ForEach function of a List...
_ListaAcaoMenuInfo.Where(p => p.Id_acao == id).ToList().ForEach(item=>item.Id_menu=0);
You wouldn't want to. LINQ is not to be used for side effects. There's a foreach loop for that.
foreach (var x in collection.where(x => x.Foo = "Blah"))
x.Foo = "Bar";
Use foreach:
var l = _ListaAcaoMenuInfo.Where(p => p.Id_acao == id).ToList();
foreach (Thing i in l)
{
i.Id_menu = 0;
//now use your Context object to save back to the database
}

Categories