Please give me a hint what return type I mention:
public IEnumerable<EMS_BUSINESSTYPE_MASTER> CustomerType(int Cust)
{
if (Cust == 1)
{
var x = (from n in db.EMS_BUSINESSTYPE_MASTER
where n.BUSINESSTYPE_ID == 1
select n).ToList();
}
else
{
var x = from n in db.EMS_BUSINESSTYPE_MASTER
select n;
}
return x;
}
Here if I provide return x I'm getting an error.
As was pointed out, x was not defined at a level that the return statement could reach. So we've just moved that out into it's own definition and ensured that the else block .ToList()'s the result. hope this helps.
public List<EMS_BUSINESSTYPE_MASTER> CustomerType(int Cust)
{
List<EMS_BUSINESSTYPE_MASTER> x = new List<EMS_BUSINESS_TYPE>();
if (Cust == 1)
{
x = (from n in db.EMS_BUSINESSTYPE_MASTER
where n.BUSINESSTYPE_ID == 1
select n).ToList();
}
else
{
x = (from n in db.EMS_BUSINESSTYPE_MASTER
select n).ToList();
}
return x;
}
I would suggest an approach like below.
x is set to one of the cases, and then if the if condition is met it is reassigned with the specific results for that scenario (i.e. business type of 1).
public IEnumerable<EMS_BUSINESSTYPE_MASTER> CustomerType(int Cust)
{
var x = db.EMS_BUSINESSTYPE_MASTER; // no need for the `select`
if (Cust == 1)
{
x = x.Where(z => z.BUSINESSTYPE_ID == 1);
}
return x;
}
The reason this helps is due to how scoping works in C#. Outside of the if and else the x (in your original code) effectively didn't exist. By declaring the x variable before the if it exists even outside of the if.
Related
I want skip my in foreach. For example:
foreach(Times t in timeList)
{
if(t.Time == 20)
{
timeList.Skip(3);
}
}
I want "jump" 3 positions in my list.. If, in my if block t.Id = 10 after skip I want get t.Id = 13
How about this? If you use a for loop then you can just step the index forward as needed:
for (var x = 0; x < timeList.Length; x++)
{
if (timeList[x].Time == 20)
{
// option 1
x += 2; // 'x++' in the for loop will +1,
// we are adding +2 more to make it 3?
// option 2
// x += 3; // just add 3!
}
}
You can't modify an enumerable in-flight, as it were, like you could the index of a for loop; you must account for it up front. Fortunately there are several way to do this.
Here's one:
foreach(Times t in timeList.Where(t => t.Time < 20 || t.Time > 22))
{
}
There's also the .Skip() option, but to use it you must break the list into two separate enumerables and then rejoin them:
var times1 = timeList.TakeWhile(t => t.Time != 20);
var times2 = timeList.SkipeWhile(t => t.Time != 20).Skip(3);
foreach(var t in times1.Concat(times2))
{
}
But that's not exactly efficient, as it requires iterating over the first part of the sequence twice (and won't work at all for Read Once -style sequences). To fix this, you can make a custom enumerator:
public static IEnumerable<T> SkipAt<T>(this IEnumerable<T> items, Predicate<T> SkipTrigger, int SkipCount)
{
bool triggered = false;
int SkipsRemaining = 0;
var e = items.GetEnumerator();
while (e.MoveNext())
{
if (!triggered && SkipTrigger(e.Current))
{
triggered = true;
SkipsRemaining = SkipCount;
}
if (triggered)
{
SkipsRemaining--;
if (SkipsRemaining == 0) triggered = false;
}
else
{
yield return e.Current;
}
}
}
Then you could use it like this:
foreach(Times t in timeList.SkipAt(t => t.Times == 20, 3))
{
}
But again: you still need to decide about this up front, rather than inside the loop body.
For fun, I felt like adding an overload that uses another predicate to tell the enumerator when to resume:
public static IEnumerable<T> SkipAt<T>(this IEnumerable<T> items, Predicate<T> SkipTrigger, Predicate<T> ResumeTrigger)
{
bool triggered = false;
var e = items.GetEnumerator();
while (e.MoveNext())
{
if (!triggered && SkipTrigger(e.Current))
{
triggered = true;
}
if (triggered)
{
if (ResumeTrigger(e.Current)) triggered = false;
}
else
{
yield return e.Current;
}
}
}
You can use continue with some simple variables.
int skipCount = 0;
bool skip = false;
foreach (var x in myList)
{
if (skipCount == 3)
{
skip = false;
skipCount = 0;
}
if (x.time == 20)
{
skip = true;
skipCount = 0;
}
if (skip)
{
skipCount++;
continue;
}
// here you do whatever you don't want to skip
}
Or if you can use a for-loop, increase the index like this:
for (int i = 0; i < times.Count)
{
if (times[i].time == 20)
{
i += 2; // 2 + 1 loop increment
continue;
}
// here you do whatever you don't want to skip
}
I've reviewed numerous articles here on SO about how to group by using a LINQ statement on a list object but the following code fails to group anything even though all the variables have the exact same values. Could someone please tell me why this might not be working? Does it have something to do with LINQ deferred execution? I've tried a sample where I included a second select statement which did not help. I'm passing in a list<MyClass> object which has two identical items and one that is not, so when this statement executes I should receive back only two items.
Actual values in the code:
Type = 1, Capacity = 50, Goal = "Teach algebra",
Attachments = "", Hours = 1, TypeDesignation = 3,
TypeControl = 1, Supplies = 0
TypeControl and Supplies are both objects themselves. Supplies is empty.
TypeControl contains Id = 23, Text = "Math", Active = 1
var test = newclass.GroupBy(n => new
{
n.Type,
n.Capacity,
n.Goal,
n.Attachments,
n.Hours,
n.TypeDesignation,
n.TypeControl,
n.Supplies
}).Distinct().Select(n => new MyClass()
{
Type = n.Key.Type,
Capacity = n.Key.Capacity,
Goal = n.Key.Goal ,
Attachments = n.Key.Attachments,
Hours = n.Key.Hours ,
TypeDesignation = n.Key.TypeDesignation,
TypeControl = n.Key.TypeControl,
Supplies = n.Key.Supplies
});
The answer to my question was that the all the objects inside were, in fact, not equal, in that I had a sub-object that during the group by one object was read as being null while the other was reading as being 0 so they never could group together but when I looked at them with intellisense they always both said null. I resolved the issue by looping through my list and using a comparer method to drill down into the sub-objects and find the differences.
VerifyDuplicates duplicates = new VerifyDuplicates();
List<MyClass> newClass = new List<MyClass>();
classes = classes.OrderBy(s => s.Type).ToList();
List<int> idsToDelete = new List<int>();
for (int i = 0; i < classes.Count; i++)
{
if (i + 1 < classes.Count)
{
var x = duplicates.Compare(classes[i], classes[i + 1]);
if (x == 1)
idsToDelete.Add(classes[i+1].Id);
}
}
newClass = classes.Where(n => !idsToDelete.Contains(n.Id)).Select(n => n).ToList();
public class VerifyDuplicates : Comparer<MyClass>
{
public override int Compare(MyClass x, MyClass y)
{
int p = 0;
if(x != null && y != null)
{
if(x.Type.Equals(y.Type)) { p += 1; }
if(x.Attachments.Equals(y.Attachments)) { p += 1; }
if(x.Capacity.Equals(y.Capacity)) { p += 1; }
if(x.Goal.Equals(y.Goal)) { p += 1; }
if(x.Hours.Equals(y.Hours)) { p += 1; }
if(x.TypeDesignation.Equals(y.TypeDesignation)) { p += 1; }
if(x.TypeControl != null && y.TypeControl != null)
if(x.TypeControl[0].Equals(y.TypeControl[0])) { p += 1; }
if(x.Supplies != null && y.Supplies!= null)
if (x.Supplies.Equals(y.Supplies)) { p += 1; }
return p;
}
}
}
I need LINQ code to be able to detect if an entry is input but the datum already exists in the table.
public Boolean CheckAssessment(String assessmentName)
{
{
SQL_TA_SCOREBOARDEntities1 d = new SQL_TA_SCOREBOARDEntities1();
Assessment A_List = new Assessment();
{
var qry2 = from b in contxt.View_Assessment
where b.AssessmentName == assessmentName
select b;
if (qry2 = assessmentName.ToString())
{
return true;
}
else
{
return false;
}
}
}
}
Where assessmentName is the value of the textbox in the a separate C# class.
Boolean i;
i = TAClass.CheckAssessment(txtAssessmentName.ToString());
if (i == true)
{
Label2.Text = "Assessment name already exists.";
}
The correct way is to use Any() extension method. Any() will generate optimized query and will return true as soon as the query found the record.
http://msdn.microsoft.com/en-us/library/bb534338.aspx
So, in your CheckAssessment method, you can do like this:
return (from b in assessments
where b.AssessmentName == assessmentName
select b).Any();
Use the Count() extension to check if there are any matching records:
public bool CheckAssessment(string assessmentName)
{
return (from b in contxt.View_Assessment
where b.AssessmentName == assessmentName
select b).Count() > 0;
}
UPDATE: just for your knowledge, your code could work this way:
public Boolean CheckAssessment(String assessmentName)
{
{
SQL_TA_SCOREBOARDEntities1 d = new SQL_TA_SCOREBOARDEntities1();
Assessment A_List = new Assessment();
{
var qry2 = (from b in contxt.View_Assessment
where b.AssessmentName == assessmentName
select b.AssessmentName).FirstOrDefault();
if (qry2 = assessmentName.ToString())
{
return true;
}
else
{
return false;
}
}
}
}
Just one more comment, always that you have something like:
if (a) { return true; } else {return false;}
you can replace by
return a;
I have a LINQ query that queries a DataTable. In the DataTable, the field is a string and I need to compare that to an integer, basically:
if ((electrical >= 100 && electrical <= 135) || electrical == 19)
{
// The device passes
}
the problem is, I am trying to do this in LINQ like this:
var eGoodCountQuery =
from row in singulationOne.Table.AsEnumerable()
where (Int32.Parse(row.Field<String>("electrical")) >= 100 &&
Int32.Parse(row.Field<String>("electrical")) <= 135) &&
Int32.Parse(row.Field<String>("electrical")) != 19 &&
row.Field<String>("print") == printName
select row;
I keep getting the exception:
Input string was not in a correct format
The main problem occurs when electrical == ""
Unfortunately, the framework doesn't provide a nice clean way to handle parsing scenarios where it fails. Of what's provided, they only throw exceptions or use out parameters, both of which does not work well with linq queries. If any one value you're parsing fails, the entire query fails and you just can't really use out parameters. You need to provide a method to handle the parsing without that does not throw and does not require using out parameters.
You can handle this in many ways. Implement it where upon failure, you return some default sentinel value.
public static int ParseInt32(string str, int defaultValue = 0)
{
int result;
return Int32.TryParse(str, out result) ? result : defaultValue;
}
Or what I would recommend, return a nullable value (null indicating it failed).
public static int? ParseInt32(string str)
{
int result;
return Int32.TryParse(str, out result) ? result : null;
}
This simplifies your query dramatically while still leaving it readable.
public bool GetElectricalStatus(string printName)
{
var query =
from row in singulationOne.Table.AsEnumerable()
where row.Field<string>("print") == printName
// using the nullable implementation
let electrical = ParseInt32(row.Field<string>("electrical"))
where electrical != null
where electrical == 19 || electrical >= 100 && electrical <= 135
select row;
return !query.Any();
}
p.s., your use of the Convert.ToInt32() method is incorrect. It is the same as calling Int32.Parse() and does not return a nullable, it will throw on failure.
I would check if the data in the column does not contain leading/trailing whitespaces - i.e. "15 " rather than "15" and if it does (or might do) trim it before trying to convert:
Int32.Parse(row.Field<String>("electrical").Trim())
BTW: not related to the error but I'd use let statement to introduce a local variable and do the conversion once:
let x = Int32.Parse(row.Field<String>("electrical").Trim())
where x >= 100...
I could not get anything to work, so I re-did the whole method:
public bool GetElectricalStatus(string printName)
{
List<object> eGoodList = new List<object>();
var eGoodCountQuery =
from row in singulationOne.Table.AsEnumerable()
where row.Field<String>("print") == printName
select row.Field<String>("electrical");
foreach (var eCode in eGoodCountQuery)
{
if (!string.IsNullOrEmpty(eCode.ToString()))
{
int? eCodeInt = Convert.ToInt32(eCode);
if (eCodeInt != null &&
(eCodeInt >= 100 && eCodeInt <= 135) || eCodeInt == 19)
{
eGoodList.Add(eCode);
}
}
}
if (eGoodList.Count() > 0)
{
return false;
}
else
{
return true;
}
}
The main problem occurs when electrical == ""
Why not make a function that does your evaluation, and call it in your Linq query. Put logic in to check the validity of the data contained within (so if you can't parse the data, it should return false)...
The function:
bool IsInRange(string text, int lower, int upper, params int[] diqualifiers)
{
int value = int.MinValue;
if (!int.TryParse(text, out value)) {
return false;
}
if (!(value >= lower && value <= upper)) {
return false;
}
if (disqualifiers != null && disqualifiers.Any(d => d == value)) {
return false;
}
return true;
}
The Linq query...
var eGoodCountQuery =
from row in singulationOne.Table.AsEnumerable()
where
IsInRange(row.Field<String>("electrical"), 100, 135, 19)
&& row.Field<String>("print") == printName
select row;
I have a list of items that I need to validate. The list can contain any number of items of the type A, B and C, but before the list can be saved, it must confirm to the following rules:
If you have A, you need either B or C
If you have B, you need A
I have ended up with the following code (saudo code):
bool IsListValid()
{
var a = list.ContainsAny(A);
var b = list.ContainsAny(B);
var c = list.ContainsAny(C);
if (!a && !b)
return true;
if (a && (b || c)
return true;
return false;
}
I don't like this code.
1. The use of Any three times in a row will potentially iterate the list three times
2. The if's doesn't look good to me.
Of cause it would be better with different variable names and by extracting the test into methods with good names, but I think there are better ways of solving this entirely. I'm just not sure how...
Any tips?
I would use a simple loop, it's both, comprehensible and efficient.
bool containsA = false, containsB = false, containsC = false;
for (int i = 0; i < list.Count; i++)
{
Type itemType = list[i].GetType();
if (!containsA) containsA = itemType == typeof(A);
if (!containsB) containsB = itemType == typeof(B);
if (!containsC) containsC = itemType == typeof(C);
if (containsA && (containsB || containsC)) return true;
}
return (!containsA && !containsB);
If it's so important that you only go through the list once, you could do this:
bool a = false;
bool b = false;
bool c = false;
foreach(var x in list)
{
if (x is A) a = true;
if (x is B) b = true;
if (x is C) c = true;
}
But I'd leave it as it is. If profiling later shows that this code is becoming a bottleneck, you can revisit it then.
As for the if's, that looks fine to me. As long as A, B and C are properly named (something like hasNotifyEmail or needsResponse, something that explains why you want them to work with the specified rules) then it should be easy for others to understand.
var hasA = list.Any(x => x.GetType() == typeof(A));
var hasB = list.Any(x => x.GetType() == typeof(B));
var hasC = list.Any(x => x.GetType() == typeof(C));
//If you have A, you need either B or C
// A AND (B xor C)
if (hasA && (hasB ^= hasC))
return true;
//If you have B, you need A
if (hasB && hasA)
return true;
return false;