Checking For null in Lambda Expression - c#

In the code below I am trying to get the null, empty string, and source components out of a List. I have not tested this code yet but my intuition tells me it will break when filtering the List for source and empty string if it comes by a null value.
I tried to extract the null values first, but I am still filtering the base List. How can I re-write this code to accomplish what I am trying to do in the best way?
List<LineItem> nullList=itemsList.Where(s => s[Constants.ProductSource] == null)
.ToList();
NALineItems = itemsList.Where(s => s[Constants.ProductSource] == source
|| s[Constants.ProductSource] == String.Empty)
.ToList();
NALineItems = nullList.Union(NALineItems).ToList();
s[Constants.ProductSource] is an attachment property to Microsoft ECommerce PurchaseOrder object. Its basically another property of an object.

Based on "I am trying to get the null, empty string, and source components out of a List" I assume you mean you want a list with these 3 specific values.
var allItems = itemsList
.Where(s => string.IsNullOrEmpty(s[Constants.ProductSource])
|| s[Constants.ProductSource] == source)
.ToList()

Is there a reason you cannot combine the expression into one? I would also add a check that the key exists in the dictionary:
List<LineItem> NALineItems = itemsList.Where(s =>
s.ContainsKey(Constants.ProductSource) && (
String.IsNullOrEmpty(s[Constants.ProductSource]) ||
s[Constants.ProductSource] == source))
.ToList();

Related

Using Linq when getting value from nested list

I need to set a variable's value to the value of a property that is nested in several Lists. Each list only has one item except for one list. I'm trying to do this:
var myValue = myListA[0].myListB[0].myListC[0].
myListD.Where(x => x.Name == "Misc Expenses").myListE[0].price;
This produces a compile time error that says myListD does not contain a definition for myListE. What is the correct syntax?
After the .Where clause, you need to to .First() (or .ToList()) in order to apply the Where clause:
var myValue = myListA[0].myListB[0].myListC[0].
myListD.Where(x => x.Name == "Misc Expenses").First().myListE[0].price;
Technically, though, you can replace that .Where with .First directly, too:
var myValue = myListA[0].myListB[0].myListC[0].
myListD.First(x => x.Name == "Misc Expenses").myListE[0].price;

Using LINQ to populate a string with a single column value

I'm a newbie both to C# and to LINQ and would appreciate a small push in the right direction.
Firstly, I have an Overrides SQL table (and a corresponding EF DB context), which has a Type, Value, and Override Value. The idea is that for a particular kind ("Type") of override, the code can check a particular value and go see if there is an override value that should be used instead.
var branchOverrides = overridesSqlContext.Overrides
.Where(q => q.Type == "Branch Override")
.Select(s => new
{
s.Value,
s.OverrideValue
});
In this case, I want the list of different override values of the "Branch Override" type. From there, I would like to be able to retrieve a specific override value at a given point within my code. How can I query the branchOverrides variable I've created to be able to say something like:
string readingOverride = select OverrideValue from branchOverrides where Value = "Reading"
My code will need to be able to read various override values for different branches at different points, and being able to query the branchOverrides variable at any point would seem like the ideal approach.
Thank you for any assistance on this.
You can use Single() on the query object you have:
string readingOverride = branchOverrides
.Single(bo => bo.Value == "Reading")
.OverrideValue;
This will throw an exception if an entry doesn't exist though so you probably want to use SingleOrDefault instead and check for a null return.
Also note that the branchOverrides object here is an IQueryable<> which means that every time you use it, it will send a query to the database. You may want to materialise that to a local list by adding .ToList() after the Select(...). Alternatively, you may want to look at caching this data, especially if it's going to be used frequently.
If I understood you right, you want the entry with Value = "Reading" and Type="Branch Override":
var branchOverride = overridesSqlContext.Overrides
.SingleOrdDefault(q => q.Type == "Branch Override"
&& q.Value == "Reading")
.Select(s => new
{
s.Value,
s.OverrideValue
});
if (branchOverride != null)
{
// do whatever ...
}
For performance issue is good to put .ToList() in the end of your LINQ expression if you need to iterante over that list too many times.
var branchOverrides = overridesSqlContext.Overrides
.Where(q => q.Type == "Branch Override")
.Select(s => new
{
s.Value,
s.OverrideValue
}).ToList();
If it you will load the entire list into the memory avoiding to execute the sql query to fetch the data if you need to iterate through your list.
Other thing that you can do is:
string readingOverride = string.Empty;
var branchOverride = branchOverrides.FirstOrDefault(x => x.Value == "Reading");
if(branchOverride != null)
{
readingOverride = branchOverride.OverrideValue;
}
Hope that helps.
If Value is unique within "Branch Override" perhaps you want to turn it to a dictionary for fast lookup
var branchOverrides = overridesSqlContext.Overrides
.Where(q => q.Type == "Branch Override")
.Select(s => new
{
s.Value,
s.OverrideValue
})
.ToDictionary(k => k.Value, v => v.OverrideValue);
Then later on you can find the override value quickly and efficiently
var readingOverride = branchOverrides["Reading"];

Entity Framework - When querying a single column, how do I tell the difference between no results and a result with a NULL value?

Let's say I have a class in EF named vw_Project with a property ProjectTitle of type string, among other properties. I want to run an efficient LINQ query which only queries the first column of the first record in my results (the first "cell", similar to SqlCommand.ExecuteScalar). I might write something like this:
string projectTitle = context.vw_Projects
.Where(p => p.ProjectID == projID)
.Select(p => p.ProjectTitle)
.FirstOrDefault();
The problem is, I can't tell whether my query got zero results, or if it simply got one result with a value of NULL for that varchar column.
I could always query the whole object to make that determination, then extract the ProjectTitle column into a string variable in memory, but I'd be querying a bunch of columns I don't need, which is a poor solution. That would look like this:
string projectTitle;
vw_Project project = context.vw_Projects
.Where(p => p.ProjectID == projID)
.FirstOrDefault();
if (project != null)
{
projectTitle = project.ProjectTitle;
}
else
{
throw new Exception("Invalid Project ID");
}
How do I make this determination without querying additional columns or rows?
You can still determine whether you got zero results or a NULL record if you create an in-line anonymous type with only the property you need.
string projectTitle;
var result = context.vw_Projects
.Where(p => p.ProjectID == projID)
.Select(p => new { p.ProjectTitle })
.FirstOrDefault();
if (result != null)
{
projectTitle = result.ProjectTitle;
}
else
{
throw new Exception("Invalid Project ID");
}
If the query gets a result, the result instance will not be null, regardless of whether the internal ProjectTitle property is null.

Can I get a property from a collection using Linq in a more elegant way than this?

I have a collection of items
List<Thing> MyListOfThings
I get this list from a db using PetaPoco like this
var MyListOfThings = db.Fetch<Thing>();
Then I want to get the value of a property like this:
otherObject.Value = MyListOfThings.SingleOrDefault(q => q.UniqueID == otherValue).SomeProperty;
I think this is a very elegant solution, the problem is if the collection does not contain an object with the UniqueID of otherValue. Then it goes BANG with a null reference exception.
The solution I have been using is
otherObject.Value = MyListOfThings.SingleOrDefault(q => q.UniqueID == otherValue) == null
? ""
: MyListOfThings.SingleOrDefault(q => q.UniqueID == otherValue).SomeProperty;
This works, Resharper still complains that there is a possible NullReferenceException, but I guess that's just because it doesn't count the first line as a nullcheck.
However... this looks ugly and is so unDRY that it's dripping...
Is there a more elegant solution for this?
It looks like SomeProperty is a string, and you want string.Empty as a fallback value. If that's right, then you can do
otherObject.Value =
(from thing in MyListOfThings
where thing.UniqueID == otherValue
select thing.SomeProperty)
.SingleOrDefault() ?? string.Empty;
The LINQ expression is an IEnumerable<string> containing the SomeProperty value of all Things having the relevant UniqueID; this might be an empty enumerable.
Use a where statement first and use DefaultIfEmpty to set your fallback value
otherObject.Value = MyListOfThings
.Where(q => q.UniqueID == otherValue)
.Select(q => q.SomeProperty)
.DefaultIfEmpty("")
.SingleOrDefault();
Do it like this
MyListOfThings object = MyListOfThings.where(q => q.UniqueID == otherValue).FirstOrDefault();
This will either get an object of my thing or null
if(!object.IsNull) // null check so wont Bang
{
//assign value here
}

how to select an item from generic list by linq

I have a LINQ query which contains a method GetInstanceForDatabase()
principlesList.Select(p => p.GetInstanceForDatabase()).ToList()
where
List<PrincipleInstance>() principlesList = ...
// (contains list of principle like "Manual Trades", "OPM", "Flora")
GetInstanceForDatabase() is a method which takes all other info about a principle (like manual trades).
My problem is that I want to sort out only principle like only "Manual Trades".
I want to put a where clause. I tried but it is fails.
To get a single item use:
query.First(x => x.property == "Manual Trades");
// or
query.FirstOrDefault(x => x.property == "Manual Trades");
var list = p.GetInstanceForDatabase().where(x => x.propertyName == "Manual Trades").ToList();
I'm sure you're GetInstanceForDatabase needs to return your collection that you then filter for the 'Manual Trades' but I can't really tell how you get your list of PrincipalInstances from the question.
This is the correct syntax of using Where in LINQ
principlesList.Select(p => p.GetInstanceForDatabase()).Where(p => p.SomeProperty == "SomeValue").ToList();

Categories