Linq to find inside Array of objects - c#

I have the below code . Here i want to find out servicelevelid in lstServiceLevels List which is an array of objects of ServiceLevelDetails where ServiceLevelName is "Basic"
Could anyone please help me to get it ?
public class ServiceLevelDetails
{
public int servicelevelid;
public string ServiceLevelName;
}
class Program
{
static void Main(string[] args)
{
IList<ServiceLevelDetails> lstServiceLevels = new List<ServiceLevelDetails>();
ServiceLevelDetails one = new ServiceLevelDetails();
one.servicelevelid=1;
one.ServiceLevelName="Basic";
ServiceLevelDetails Two = new ServiceLevelDetails();
Two.servicelevelid = 2;
Two.ServiceLevelName = "Enhanced";
lstServiceLevels.Add(one);
lstServiceLevels.Add(Two);
var test = from LevelName in lstServiceLevels
let LevelName= obj as ServiceLevelDetails
where LevelName.ServiceLevelName == "Basic"
select LevelName;
//getting error in the above code .
}
}

There is nothing in your scope called obj, so it's not clear why this is in your query.
In LINQ query syntax, it sounds like you want this:
from serviceLevel in lstServiceLevels
where serviceLevel.ServiceLevelName == "Basic"
select serviceLevel;
Or in LINQ method syntax:
lstServiceLevels.Where(x => x.ServiceLevelName == "Basic");
If, as you suggest in the comments, you want the id for a specific name:
var id = lstServiceLevels
.Where(x => x.ServiceLevelName == "Basic")
.Select(x => x.servicelevelid)
.Single();

here is an alternative with which you don't run into exceptions
when the element cannot be found.
look for the first occurrence of this element:
// FirstOrDefault will return null if nothing was found
// but it also will return only the first element!
var id_test = lstServiceLevels.FirstOrDefault(x => x.ServiceLevelName == "Basic");
// then you can check for it and take the ID if it was found
// or else assign some other value
int id = id_test != null ? id_test.servicelevelid : 0;
it's of course a matter of taste either to use try/catch or null testing :)

Related

Linq code doesn't return correct record

I have a table named dbo.EmployeeType with three records:
PK_EmployeetypeID EmployeeTypeName
1 Project Manager
2 Business Analyst
3 Developer
I have this piece of Linq code:
public static string GetTypeByID(int id)
{
using (ProjectTrackingEntities1 db = new ProjectTrackingEntities1())
{
var type = db.EmployeeTypes.Select(o => new LOOKUPEmployeeType
{
PK_EmployeeTypeID = id,
EmployeeTypeName = o.EmployeeTypeName
});
return type.FirstOrDefault().EmployeeTypeName;
}
}
No matter what id I send to it, it returns Project Manager, and I'm confused as to why.
You need to apply a filter, otherwise you're just returning the first record and hard coding the ID. Try this:
public static string GetTypeByID(int id)
{
using (ProjectTrackingEntities1 db = new ProjectTrackingEntities1())
{
//Here we apply a filter, the lambda here is what creates the WHERE clause
var type = db.EmployeeTypes
.FirstOrDefault(et => et.PK_EmployeeTypeID == id);
if(type != null)
{
return type.EmployeeTypeName;
}
else
{
return "";
}
}
}
Note that using FirstOrDefault means if there are no matches, or multiple matches, type will be null and you will get an empty string returned.
Set a breakpoint on type = ... and inspect it. You have no Where in there so you get all - and Select just makes LOOKUPEmployeeTypes out of all of them.
FirstOrDefault then returns the first of those 3 which is always the ProjManager
Fix:
var type = db
.EmployeeTypes
.Where( o => o.Id == id)
.Select(o => new LOOKUPEmployeeType
{
PK_EmployeeTypeID = id,
EmployeeTypeName = o.EmployeeTypeName
});
In your code you only return the first value. You need to tell EF which value you need to return.
Let us assume you need the value with Id=2. Instead of Select(), use Single(x => x.Id == 2) or First(x => x.Id == 2).

Linq - Conditional Where / Find

I have the following 2 lines,
var productStrucutre = _service.GetProductStructureWithParent(partId).ToList(); // returns a list of objects
var product = productStrucutre.Find(_ => _.Part == part); // Returns a part
if the following condition fails because the part does not exist, then i would like to return the whole product structure.
var product = productStrucutre.Find(_ => _.Part == part);
So the find will fall away
I assume you mean something like this:
var productStructure = _service.GetProductStructureWithParent(partId).ToList();
var product = productStrucutre.Where(x => x.Part == part);
return product.Any() ?
product : // return only those products that fit the condition
productStructure; // return all objects

How to find the max-ID by using a lambda-query?

I wanna find the next ID (ID_Titel) by selecting ID_Artiest. I try it by using LINQ (lambda-query). What do I do wrong.
By example:
For ID_Artiest 2, I wanna have ID_Titel n+1.
First I try it without .DefaultIfEmpty(). and then I get a message: Sequence Contains No Element
Second I try it with .DefaultIfEmpty().: And then I get the message: Object reference not set to an instance of an object.
This is the source:
private void UpdateTitel(NoteringDataType itemDezeWeek)
...
...
TitelDataType titel = new TitelDataType();
if (Titelslijst.Count > 0)
titel.ID_Titel = Titelslijst.Where(t => t.ID_Artiest == itemDezeWeek.ID_Artiest).OrderBy(t => t.ID_Titel).DefaultIfEmpty().Max(t => t.ID_Titel) + 1;
else
titel.ID_Titel = 1;
Both of the errors you got are expected if the first Where doesn't find any matching values.
Please try this:
titel.ID_Titel = Titelslijst.Where(t => t.ID_Artiest == itemDezeWeek.ID_Artiest)
.Select(t => t.ID_Titel)
.OrderByDescending(t => t)
.FirstOrDefault() + 1;
Since the Select transforms the collection to an enumeration of ints (I am assuming), the .FirstOrDefault() should return 0 if the Where() didn't return any matches. In your code, .DefaultIfEmpty() would have returned an IEnumerable<T> containing null because it was called on an enumeration of whatever Titelslijst contains.
Apparently the errors you see happen when nothing in the list matches your where condition. DefaultIfEmpty in this case will give you just a single list with null, which does not help a lot.
To avoid such situations you should really assign ID to 1 if there no entries found. So the logic should be like:
TitelDataType titel = new TitelDataType();
int id = 1;
if (Titelslijst.Count > 0)
{
var titles = Titelslijst.Where(t => t.ID_Artiest == itemDezeWeek.ID_Artiest);
if (titles.Any())
id = titles.Max(t => t.ID_Titel) + 1;
}
titel.ID_Titel = id;
More short, more right:
Titelslijst.Where(t => t.ID_Artiest == itemDezeWeek.ID_Artiest).Select(t => t.ID_Artiest).Max();

List<string> get item that starts with Name= using LINQ

How can i retrieve from a List<string> the item(value) that starts with Name=
If the list contains the values:
Name=Jhon Smith
Age=20
Location=CityName
I want to get the value Jhon Smith.
I do know how to traditionally loop through the list using foreach and have a condition if value starts with Name= ... but I'm not that good with LINQ.
This will throw an exception if there is no such element in the collection.
You can use FirstOrDefault and check if you get null or an element to check
whether there was a match or not.
list.First(x => x.StartsWith("Name=")).Substring(5)
This won't throw an exception:
var prefix = "Name=";
var elem = list.FirstOrDefault(item => item.StartsWith(prefix));
if (elem != null) {
return elem.Substring(prefix.Length)
} else {
return null;
}
Use Single or SingleOrDefault like this:
var result = list.Single(s => s.StartsWith("Name=")).Substring(5);
or
string result = string.Empty;
var element = list.SingleOrDefault(s => s.StartsWith("Name="));
if (element == null)
{
//"Name=" not present, throw an exception
}
result = element.Substring(5);
or similarly with First, or FirstOrDefault depending on what you exactly want.
There was another interesting answer by the user canon, but was deleted (I don't know why):
var result = list
.Where(x => x.StartsWith("Name="))
.Select(x => x.Substring(5))
.FirstOrDefault();
Its advantage is that it won't throw regardless of the input data.
String match = list.FirstOrDefault( str => str.IndexOf("Name=", StringComparison.InvariantCulture) > -1 );
return match.Substring("Name=".Length);

Dynamic where clause in LINQ to Objects

I know there are a lot of examples of this on the web, but I can't seem to get this to work.
Let me try to set this up, I have a list of custom objects that I need to have limited on a range of values.
I have a sort variable that changes based on some action on the UI, and I need to process the object differently based on that.
Here is my object:
MyObject.ID - Just an identifier
MyObject.Cost - The cost of the object.
MyObject.Name - The name of the object.
Now I need to filter this based on a range in the cost, so I will have something similar to this, considering that I could be limiting by Either of my bottom two properties.
var product = from mo in myobject
where mo.Cost <= 10000
or
var product = from mo in myobject
where mo.Name equals strName
Now I have the dynamic linq in my project, but I'm not figuring out how to get it to actually work, as when I do some of the examples I am only getting:
Func<Tsourse>bool> predicate
as an option.
Update:
I am trying to find a solution that helps me Objectify my code, as right now it is a lot of copy and paste for my linq queries.
Update 2:
Is there an obvious performance difference between:
var product = from mo in myobject
... a few joins ...
where mo.Cost <= 10000
and
var product = (from mo in myobject
... a few joins ...)
.AsQueryable()
.Where("Cost > 1000")
Maybe not directly answering your question, but DynamicQuery is unnecessary here. You can write this query as:
public IEnumerable<MyObject> GetMyObjects(int? maxCost, string name)
{
var query = context.MyObjects;
if (maxCost != null)
{
query = query.Where(mo => mo.Cost <= (int)maxCost);
}
if (!string.IsNullOrEmpty(name))
{
query = query.Where(mo => mo.Name == name);
}
return query;
}
If the conditions are mutually exclusive then just change the second if into an else if.
I use this pattern all the time. What "Dynamic Query" really means is combining pure SQL with Linq; it doesn't really help you that much with generating conditions on the fly.
using System.Linq;
var products = mo.Where(x => x.Name == "xyz");
var products = mo.Where(x => x.Cost <= 1000);
var products = mo.Where(x => x.Name == "xyz" || x.Cost <= 1000);
Read this great post on DLINQ by ScottGu
Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library)
You would need something like
var product = myobject.Where("Cost <= 10000");
var product = myobject.Where("Name = #0", strName);
If you downloaded the samples you need to find the Dynamic.cs file in the sample. You need to copy this file into your project and then add
using System.Linq.Dynamic; to the class you are trying to use Dynamic Linq in.
EDIT: To answer your edit. Yes, there is of course a performance difference. If you know the variations of filters beforehand then I would suggest writing them out without using DLINQ.
You can create your own Extension Method like so.
public static class FilterExtensions
{
public static IEnumerable<T> AddFilter<T,T1>(this IEnumerable<T> list, Func<T,T1, bool> filter, T1 argument )
{
return list.Where(foo => filter(foo, argument) );
}
}
Then create your filter methods.
public bool FilterById(Foo obj, int id)
{
return obj.id == id;
}
public bool FilterByName(Foo obj, string name)
{
return obj.name == name;
}
Now you can use this on an IEnumerable<Foo> very easily.
List<Foo> foos = new List<Foo>();
foos.Add(new Foo() { id = 1, name = "test" });
foos.Add(new Foo() { id = 1, name = "test1" });
foos.Add(new Foo() { id = 2, name = "test2" });
//Example 1
//get all Foos's by Id == 1
var list1 = foos.AddFilter(FilterById, 1);
//Example 2
//get all Foo's by name == "test1"
var list2 = foos.AddFilter(FilterByName, "test1");
//Example 3
//get all Foo's by Id and Name
var list1 = foos.AddFilter(FilterById, 1).AddFilter(FilterByName, "test1");

Categories

Resources