How to safely convert to Integer possible null values [duplicate] - c#

This question already has answers here:
Better way to cast object to int
(12 answers)
Closed 3 years ago.
var data = mockDataDB.Data.AsQueryable()
.Select(x => new ProductDto
{
Id = Convert.ToInt64(x.id), // this might fail because id might be null
Quantity = Int32.TryParse(x.quantity, out int somenumber) ? x.quantity : (int?)null
}
Issue with this code is that x.id and x.quantity might be null sometimes, they are both of type string and id and quantity are type of int64 and int32..
How could I safely solve this?
Thanks
cheers

You could inline a TryParse with a ternary expression, provided you have a default value in mind for Id when it's null.
var data = mockDataDB.Data.AsQueryable()
.Select(x => new ProductDto
{
Id = Int64.TryParse(x.id, out long val) ? val : 0L,
Quantity = Int32.TryParse(x.quantity, out int somenumber) ? somenumber : (int?)null
}

Something like this: Id = Int64.TryParse(x.id, out int somenumber) ? somenumber : 0

Edited:
You should check if the String variable (x.id) is null. If it is, you set it to zero or some default value that you would want. If its not, proceed with the converting.
For example:
Id = (x.id == null) ? 0 : Convert.ToInt64(x.id);

Related

Split string and convert to nullable long

I have the following code which splits a string and then convert the values to long:
string.IsNullOrEmpty(baIds) ? null : baIds.Split(',').Select(e => long.Parse(e)).ToList(),
What I want is to convert the values to nullable long instead.
Any help pls?
If you just need it to be typed as long? then just cast in the Select
Select(e => (long?)long.Parse(e))
If you need to use null to indicate something that couldn't be parsed as long then
Select(e => long.TryParse(e, out long r) ? r : default(long?))
Use TryParse
List<long?> result = null;
if (!string.IsNullOrEmpty(baIds))
{
long temp;
result = baIds.Split(',').Select(e => long.TryParse(e, out temp) ? temp : (long?)null).ToList();
}
https://dotnetfiddle.net/uHk99J
You can use this,
string.IsNullOrEmpty(baIds) ? null : baIds.Split(',').Select(e => (long?)long.Parse(e)).ToList(),

Casting short to boolean entity framework

I am trying to convert a short value which represents a true or false in our system, -1(true), 0(false).
I was wondering if this kind of casting/conversion is possible inline where model property is being initialized.
public bool Foo {get;set;}
example:
return db.tblSomeTable
.Where( c => c.FooID == 1)
.Select( c => new SomeFooModel
{
FooID = id,
Foo = IsTrueOrFalse //value (-1, or 0)
}
I tried using a ternary operator but the syntax doesn't make sense:
IsFoo = if(IsTrueOrFalse == -1) ? true: false;, //syntax error it is obvious that ; is ending statement but the , there because there are more properties in this select.
The other way to do this might be to call a function that return true or false based on value passed in but I was wondering if this can be done with minimum lines of code.
Any suggestions?
Thanks
You can use a boolean expression
.Select(c => new SomeFooModel
{
Foo = (IsTrueOrFalse == -1)
}
or the conditional operator
.Select(c => new SomeFooModel
{
Foo = (IsTrueOrFalse == -1) ? true : false
}
The ternary statement is written like so:
IsFoo = (IsTrueOrFalse == -1) ? true : false
i.e. there is no need for the if and because there are other statements you also do not need the semi colon.
EDIT
As #juharr said in a comment if the value is anything other than -1, IsFoo will be set to false. So maybe you should do some extra checks. For example:
IsFoo = (IsTrueOrFalse == -1) ? true : (IsTrueOrFalse == 0) ? false : throw new ArgumentOutOfRangeException() //Or whatever
Although that will become unreadable fast.

Depth of a relationship

I'm trying to figure out how to get the depth of a relationship of an entity that can relate to itself. That is There is a base comment item, which can have one or more reply comments linked to it.
Now for each one of these replied comments I want to know how deep they are from the top node.
ie, I want to know the Depth in the comments in the image below:
This is the code as of now, and the variable ResponseTo is the relationship that this comment is a response to, if is is not a response the value is null
var comments = db.Comments
.Where(c => c.Post.ID == id && c.Status == Helpers.StatusCode.Visible)
.Select(x => new CommentTemp()
{
Id = x.ID,
Text = x.Text,
Avatar = "-1",
Username = (x.User != null ? x.User.UserName : "Anonymous"),
UserID = (x.User != null ? (int?) x.User.Id : null),
ResponseTo = (x.ResponseTo == null ? null : (int?) x.ResponseTo.ID),
CommentDepth = ??? // <--- how do i select the depth of the response to relations?
Created = x.Created
})
.ToList();
Only option I can think of right now is saving it as the comment is created, but if possible I would like to get it on the fly.
Well, it indeed sounds like you want to hold such information in the database, unless there's really good reason not to. Either way, Linq is not really recursive friendly.
You can get the depth by creating dictionary & tracking it back recursively.
int GetDepth(Comment comment,
IDictionary<int, Comment> comments, /*key=commentId, val=Comment*/
IDictionary<int, int> depthMemoization, /* key=commentId, val=depth*/
int currentDepth = 0)
{
if(depthMemoization.ContainsKey(comment.Id))
return depthMemoization[comment.Id];
if(comment.ParentId==null)
return currentDepth;
var parentComment = comments[comment.ParentId.Value];
int calculatedDepth = GetDepth(parentComment, comments,
depthMemoization,
++currentDepth);
depthMemoization[comment.Id] = calculatedDepth ;
return depth;
}

DataTable Custom LINQ OrderBy

I keep getting object not set to an instance of an object and I'm not sure why.
SortColumn datatype string Data: "123|bob", DBNull.Value, "234|sam",
"345|jim"
I have this so far:
table = table.AsEnumerable().OrderBy(
o => o.Field<object>(sortColumn) ==
DBNull.Value ? 99999 : o.Field<string>(sortColumn).Split('|')[0].TryParse(0)
).CopyToDataTable();
public static int TryParse(this string input, int valueIfNotConverted)
{
int value;
if (Int32.TryParse(input, out value))
{
return value;
}
return valueIfNotConverted;
}
Basically want to sort the part before | in ascending order (CopyToDataTable() returns the sorted table)
I believe the Field<> extension method handles DBNull for you, so you can just check for a null value (more information):
... o.Field<object>(sortColumn) == null ? 99999 ...
On a side note, you can avoid the double field access by selecting all of the column values first, then doing the split:
table
.AsEnumerable()
.Select(row => row.Field<string>(sortColumn))
.OrderBy(value => value == null ? 99999 : Convert.ToInt32(value.Split('|').First()));

Max return value if empty query

I have this query:
int maxShoeSize = Workers
.Where(x => x.CompanyId == 8)
.Max(x => x.ShoeSize);
What will be in maxShoeSize if company 8 has no workers at all?
UPDATE:
How can I change the query in order to get 0 and not an exception?
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
.Select(x => x.ShoeSize)
.DefaultIfEmpty(0)
.Max();
The zero in DefaultIfEmpty is not necessary.
I know this is an old question and the accepted answer works, but this question answered my question about whether such an empty set would result in an exception or a default(int) result.
The accepted answer however, while it does work, isn't the ideal solution IMHO, which isn't given here. Thus I am providing it in my own answer for the benefit of anyone who is looking for it.
The OP's original code was:
int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max(x => x.ShoeSize);
This is how I would write it to prevent exceptions and provide a default result:
int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max(x => x.ShoeSize as int?) ?? 0;
This causes the return type of the Max function to be int?, which allows the null result and then the ?? replaces the null result with 0.
EDIT
Just to clarify something from the comments, Entity Framework doesn't currently support the as keyword, so the way to write it when working with EF would be:
int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max<[TypeOfWorkers], int?>(x => x.ShoeSize) ?? 0;
Since the [TypeOfWorkers] could be a long class name and is tedious to write, I've added an extension method to help out.
public static int MaxOrDefault<T>(this IQueryable<T> source, Expression<Func<T, int?>> selector, int nullValue = 0)
{
return source.Max(selector) ?? nullValue;
}
This only handles int, but the same could be done for long, double, or any other value type you need. Using this extension method is very simple, you just pass in your selector function and optionally include a value to be used for null, which defaults to 0. So the above could be rewritten like so:
int maxShoeSize = Workers.Where(x => x.CompanyId == 8).MaxOrDefault(x => x.ShoeSize);
Hopefully that helps people out even more.
Max() won't return anything in that case.
It will raise InvalidOperationException since the source contains no elements.
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
.Select(x => x.ShoeSize)
.DefaultIfEmpty()
.Max();
If this is Linq to SQL, I don't like to use Any() because it results in multiple queries to SQL server.
If ShoeSize is not a nullable field, then using just the .Max(..) ?? 0 will not work but the following will:
int maxShoeSize = Workers.Where(x = >x.CompanyId == 8).Max(x => (int?)x.ShoeSize) ?? 0;
It absolutely does not change the emitted SQL, but it does return 0 if the sequence is empty because it changes the Max() to return an int? instead of an int.
int maxShoeSize=Workers.Where(x=>x.CompanyId==8)
.Max(x=>(int?)x.ShoeSize).GetValueOrDefault();
(assuming that ShoeSize is of type int)
If Workers is a DbSet or ObjectSet from Entity Framework your initial query would throw an InvalidOperationException, but not complaining about an empty sequence but complaining that the materialized value NULL can't be converted into an int.
Max will throw System.InvalidOperationException "Sequence contains no elements"
class Program
{
static void Main(string[] args)
{
List<MyClass> list = new List<MyClass>();
list.Add(new MyClass() { Value = 2 });
IEnumerable<MyClass> iterator = list.Where(x => x.Value == 3); // empty iterator.
int max = iterator.Max(x => x.Value); // throws System.InvalidOperationException
}
}
class MyClass
{
public int Value;
}
NB: the query with DefaultIfEmpty() may be significantly slower.
In my case that was a simple query with .DefaultIfEmpty(DateTime.Now.Date).
I was too lazy to profile it but obviously EF tried to obtain all the rows and then take the Max() value.
Conclusion: sometimes handling InvalidOperationException might be the better choice.
You can use a ternary within .Max() to handle the predicate and set its value;
// assumes Workers != null && Workers.Count() > 0
int maxShoeSize = Workers.Max(x => (x.CompanyId == 8) ? x.ShoeSize : 0);
You would need to handle the Workers collection being null/empty if that's a possibility, but it would depend on your implementation.
You can try this:
int maxShoeSize = Workers.Where(x=>x.CompanyId == 8).Max(x => x.ShoeSize) ?? 0;
You could check if there are any workers before doing the Max().
private int FindMaxShoeSize(IList<MyClass> workers) {
var workersInCompany = workers.Where(x => x.CompanyId == 8);
if(!workersInCompany.Any()) { return 0; }
return workersInCompany.Max(x => x.ShoeSize);
}

Categories

Resources