check whether LINQ query returns rows - c#

I need to check whether a query returns rows and if it does, change it to a string, but if it doesn't, return "In Progress". I thought the below code would work but this is always true:
if (System.Linq.Enumerable.Count(columns) == 0)<--- always true but it shouldn't be
And when there isn't a row returned to columns I get the following error in my jQuery Ajax:
"The cast to value type \u0027Int32\u0027 failed because the materialized value is null. Either the result type\u0027s generic parameter or the query must use a nullable type."
Here's my WebMethod:
using (dbPSREntities5 myEntities = new dbPSREntities5())
{
var thisId = myEntities.tbBreadCrumbs.Where(x => x.ProjectID == projectID && x.StatusID == statusID).Max(x => x.BreadCrumbID);
var columns = myEntities.tbBreadCrumbs
.Where(x => x.BreadCrumbID == thisId)
.Select(x => x.CreateDateTime)
.ToList();
if (System.Linq.Enumerable.Count(columns) == 0)
{
var formattedList = columns
.Select(d => null != d
? d.Value.ToString("MMM dd, yyyy")
: string.Empty) // this is just one example to handle null
.ToList();
return formattedList;<-- return this if there is a BreadCrumbID (columns would have a row)
}
else
{
return "In Progress";<--- there was no BreadCrumbID (columns would have 0 rows)
}
}

You could use Any()
MSDN Enumerable.Any Method

You first check for Count == 0, doesn't sound right, I guess you need the opposite check. You should use Any or Count() > 0 check, Like:
if (columns.Any()) //Or columns.Count() > 0
{
var formattedList = columns
.Select(d => null != d
? d.Value.ToString("MMM dd, yyyy")
: string.Empty) // this is just one example to handle null
.ToList();
return formattedList;<-- return this if there is a BreadCrumbID (columns would have a row)
}
else
{
return "In Progress";<--- there was no BreadCrumbID (columns would have 0 rows)
}
You have to convert your List to string, in order for your method to return a string.

Your condition is wrong. Count must be greater than zero

Use the .Any() method provided by List<T>:
If (columns.Any())
{
// do your bidding
} else {
// in progress code
}
Also your method has two different return signatures. That won't compile. You can't return a List or a string, unless the return type is object (not recommended).
I suggest to return a null list and check if it's null in your UI layer and then display the appropriate string or date values, since they end up as strings in the UI anyway.

You only needs to ckeck .Count() > 0
if (columns.Count() > 0)
{
var formattedList = columns
.Select(d => null != d
? d.Value.ToString("MMM dd, yyyy")
: string.Empty) // this is just one example to handle null
.ToList();
return formattedList;<-- return this if there is a BreadCrumbID (columns would have a row)
}
else
{
return "In Progress";<--- there was no BreadCrumbID (columns would have 0 rows)
}

Related

Find record based on value from the table

This is my code to find string in my UserTable.
var PhoneExists = _db.UserTable.Where(u => u.PhoneNumber == Input.PhoneNumber);
and this is my if code:
if (PhoneExists != null)
{
ErrorAlert("number found.");
return Page();
}
but every time the if condition is true.
It returns true as PhoneExists is not null, but it returns with IQueryable value.
You need to materialize the query to return the result queried from the database.
You may look for .Any() to find whether there is any record with the respective PhoneNumber existed.
bool PhoneExists = _db.UserTable.Any(u => u.PhoneNumber == Input.PhoneNumber);
if (PhoneExists)
{
...
}
Where will always return a non-null enumerable, and it's empty if there are no matches. You have to check its contents. If you expect the phone numbers to be unique, you could use FirstOrDefault or SingleOrDefault to return either a string, or null. The latter will, however, throw if there is more than one match.
You can use Contains here.
Sample code:
var PhoneExists = _db.UserTable.Where(u => u.PhoneNumber.Contains(Input.PhoneNumber)).FirstOrDefault();
In your if code:
if (PhoneExists != null && PhoneExist.Count()== 0)
{
ErrorAlert("number found.");
return Page();
}
You can use Exists instead of Where like this :
if (_db.UserTable.Exists(u => u.PhoneNumber == Input.PhoneNumber))
{
//Do Something
}
About exist checkout https://learn.microsoft.com/tr-tr/dotnet/api/system.collections.generic.list-1.exists?view=net-6.0
You can use FirstOrDefault()
var PhoneExists = _db.UserTable.Where(u => u.PhoneNumber == Input.PhoneNumber).FirstOrDefault();

LINQ .Where .Max and Writing to File

I have a program which writes its output to log files to folders in the following format:
Car7 Lap1 00-00-21-5290000
Everything is working fine, but I want to append a # to the filename of the fastest lap time for each car. In order to do so, I placed the following LINQ query inside my car object to act on the List property of Car:
public List<Lap> Laps { get; set; } = new List<Lap>();
public TimeSpan FastestLap => Laps.Where(lap => lap.Number is not null and not 0).Min(lap => lap.LapTime);
I'm using the .Where clause as laps can sometimes be null or 0, and when I write to disk things initially appear to be working:
Car8 Lap39 00-01-07-8900000#
However, only 8 cars get written to disk as opposed to the full field of 20 cars. If I remove only the .Where part of my property above, all the cars and car folders write properly, except the Lap 0 files are typically marked as the fastest lap (which makes sense since they contain incomplete times).
My writing to disk method looks like this:
foreach (var car in carList)
{
Directory.CreateDirectory(#$"{outputPath}\{logFileName}\Car{car.Number}");
foreach (var lap in car.Laps)
{
using TextWriter tw = new StreamWriter(#$"{outputPath}\{logFileName}\Car{car.Number}\Car{car.Number} Lap{lap.Number} {lap.LapTime.ToString().Replace(":", "-").Replace(".", "-")}{(lap.LapTime == car.FastestLap ? "#" : "")}.csv");
WriteCsvHeader(tw);
foreach (var telemetryRecord in lap.UniqueTelemetryRecords)
{
WriteCsvLine(tw, lap, telemetryRecord);
}
}
}
Is there a way to prevent this from happening so that all cars and car folders get written to disk?
In this case, use a getter to perform a bit more advanced logic when retrieving the value.
Replace this line:
public TimeSpan FastestLap => Laps.Where(lap => lap.Number is not null and not 0).Min(lap => lap.LapTime);
With this:
public TimeSpan FastestLap
{
get
{
if(Laps.Where(lap => lap.Number is not null and not 0).Count() > 0)
return Laps.Where(lap => lap.Number is not null and not 0).Min(lap => lap.LapTime);
else
return Laps.Min(lap => lap.LapTime);
}
}
This is essentially saying that if any non zero laps exist, get the lowest value. Otherwise, it'll just return the zero value.
One option would be to implement IComparable<T> on your class:
public class Lap : IComparable<Lap>
{
public int CompareTo(Lap other)
{
//if both have nulls or zero they are equal
if((this.Number == null || this.Number == 0) && (other == null || other.Number == null || other.Number == 0) return 0;
// If other is null or the other.Number is null or zero this instance is first in sort order
if (other == null || other.Number == null || other.Number == 0) return -1;
//if this instance has null or zero for the number and other doesn't this instance comes after other
if((this.Number == null || this.Number == 0) && other != null && other.Number != null && other.Number != 0) return 1;
//Comparison depends on this.LapTime to other.LapTime
return LapTime.CompareTo(other.LapTime);
}
......
}
Then you could just call .Sort() on the List<Lap> and your first item in the List will be your fastest lap that is not null or zero. Append the # to the first item in the list and you don't need an extra method in your class.

unable to cast of type 'System.Data.EnumerableRowCollection`1[System.String]' to type 'System.IConvertible'

I need the column value(FundSpreadDurationContribution) of a data table(residing in dataset) through LINQ which fetches the above error (heading)
Elaborated: when a row cell has value Spread Duration--IR Swap, need the corresponding column cell FundSpreadDurationContribution value.
double testvalue = Convert.ToDouble(raptorDS.Tables[RaptorTable.DurationContribBySector].AsEnumerable().Where(r =>
r.Field<string>(RaptorColumns.FundCode) == fundDescriptionColumn &&
r.Field<string>(RaptorColumns.Component) == Component.B8_DURATION_CONTRIBUTION_BY_SECTOR &&
r.Field<string>(RaptorColumns.Sector) == "Spread Duration--IR Swap").Select(s => s.Field<string>(RaptorColumns.FundSpreadDurationContribution)))
I am learner of LINQ.
// First check if this query will return any results
var records =
raptorDS.Tables[RaptorTable.DurationContribBySector].AsEnumerable().Where(r =>
r.Field<string>(RaptorColumns.FundCode) == fundDescriptionColumn &&
r.Field<string>(RaptorColumns.Component) == Component.B8_DURATION_CONTRIBUTION_BY_SECTOR &&
r.Field<string>(RaptorColumns.Sector) == "Spread Duration--IR Swap");
// CHeck if any result
if (records.Any())
{
// We have results so let's go through each record and try to get that value
// converted to a double
List<double> values = new List<double>();
List<string> badValues = new List<string>();
foreach (var thisRecord in records)
{
var fsdc = thisRecord.Field<string>(RaptorColumns.FundSpreadDurationContribution);
if (!string.IsNullOrWhiteSpace(fsdc))
{
double val = 0;
if (double.TryParse(fsdc, val))
{
values.Add(val);
}
else
{
badValues.Add(fsdc);
}
}
}
// Do whatever you need to do with values here
// and bad values here
}
Where returns a collection, which cannot be converted to a double. Use one of these Linq methods to get one answer to convert:
Single
SingleOrDefault
First
FirstOrDefault
This is just playing around with Datatypes which fixed the type casting issue
var sumFundSpreadDuration = raptorDS.Tables[RaptorTable.DurationContribBySector].AsEnumerable().Where(r =>
r.Field<string>(RaptorColumns.FundCode) == fundDescriptionColumn &&
r.Field<string>(RaptorColumns.Component) == Component.B8_DURATION_CONTRIBUTION_BY_SECTOR &&
r.Field<string>(RaptorColumns.Sector) == "Spread Duration--IR Swap")
.Select(s => s.Field<double?>(RaptorColumns.FundSpreadDurationContribution)).FirstOrDefault();
If you see the datatype of variable is changed to Variant from double. Also, the datatype of column FundSpreadDurationContribution is changed to double. Thanks to CodingYoshi for providing insights of datatypes in linq

Cannot implicitly convert type 'string' to 'bool' [If statement]

I have this validation in mvc
public static ValidationResult validaUsuariosNaLista(Reuniao item)
{
var requeridos = item.Requeridos.Select(x => x.Login).Any();
var informados = item.Informados.Select(y => y.Login).Any();
var opcionais = item.Opcionais.Select(z => z.Login ? z.Login : null).Any();
if (requeridos == informados || requeridos == opcionais || informados == opcionais)
return new ValidationResult(Resources.Validations.ValidaUsuarioMesmaLista);
return ValidationResult.Success;
}
I try make a different if in line
var opcionais = item.Opcionais.Select(z => z.Login ? z.Login : null).Any();
but show error
Error 3 Cannot implicitly convert type 'string' to 'bool'
z.Login is a string
validation is to make that the field has no value it receives null.
Without that it bursts the error that is null.
I want him to receive null without giving error for it.
It selects the z.login on the list if the same login is in the other lists he'm the error.
How can I do this "if" that way?
If z.Login is a string, then this expression is invalid:
z.Login ? z.Login : null
The first element in that expression needs to be a bool. What exactly are you trying to examine in that condition? Whether or not z.Login is null? If that's the case then you don't need a condition at all:
.Select(z => z.Login)
Since you'd just be replacing null with, well, null. Or if you want to interpret empty strings as null then you can use something like this:
.Select(z => string.IsNullOrEmpty(z.Login) ? nulll : z.Login)
Though it's not really clear what you're trying to accomplish with this line of code in the first place. .Any() is going to return a bool indicating whether or not any matching element exists in the collection at all. But since you're not using a predicate in .Any(), it's going to return true if there is any element in the collection at all. Which not only renders the .Select() pointless, but also doesn't tell you anything about that condition in the .Select().
Perhaps you are trying to find if there are any null values in the collection?:
item.Opcionais.Any(z => z.Login == null)
or any "null or empty" values?:
item.Opcionais.Any(z => string.IsNullOrEmpty(z.Login))
or the opposite, any non-empty values?:
item.Opcionais.Any(z => !string.IsNullOrEmpty(z.Login))
and so on...
z.Login is a string
validation is to make that the field has no value it receives null.
Do it like this:
Edit: Updated this section to also look for duplicates
public static ValidationResult validaUsuariosNaLista(Reuniao item)
{
var requeridos = item.Requeridos.Any(x => string.IsNullOrWhiteSpace(x.Login));
var informados = item.Informados.Any(x => string.IsNullOrWhiteSpace(x.Login));
var opcionais = item.Opcionais .Any(x => string.IsNullOrWhiteSpace(x.Login));
//does every item have a value?
if (requeridos || informados || opcionais)
return new ValidationResult(Resources.Validations.ValidaUsuarioMesmaLista);
//are all of the items unique?
if (item.Requeridos.Count() + item.Informados.Count() + item.Opcionais.Count() >
item.Requeridos.Concat(item.Informados).Concat(item.Opcionais).Distinct().Count)
{
//some items are duplicated
}
return ValidationResult.Success;
}
And, for fun, to avoid repeating code:
public static ValidationResult validaUsuariosNaLista(Reuniao item)
{
var HasEmptyValue = s => s.Any(x => string.IsNullOrWhiteSpace(x.Login));
//does every item have a value?
if (HasEmptyValue(item.Requeridos) || HasEmptyValue(item.Informados) || HasEmptyValue(item.Opcionais))
return new ValidationResult(Resources.Validations.ValidaUsuarioMesmaLista);
//are all of the items unique?
if (item.Requeridos.Count() + item.Informados.Count() + item.Opcionais.Count() >
item.Requeridos.Concat(item.Informados).Concat(item.Opcionais).Distinct().Count)
{
//some items are duplicated
}
return ValidationResult.Success;
}
Though I'm not 100% on how well type inference will work here... I'd have to see what the compiler makes of it, and I don't have your types to test with. But at worst, you'd just have to be explicit on the var declaration.
I think what you're trying to do is check if Login is null or empty. Assuming you want opcionais to be a boolean based on your .Any() statement:
var opcionais = item.Opcionais.Select(z => z.Login ? z.Login : null).Any();
should be
var opcionais = item.Opcionais.Any(z => !string.IsNullOrEmpty(z.Login));

LINQ return 0 if query from DataTable is null

Hi Everyone I have the following query. On occasion, there are no results for this query, and I will need it to return a 0, rather than an error.
var count= dt.AsEnumerable().Where(x => x.Field<string>("names").Equals(name) && x.Field<string>("port").Equals("true")).Count();
I have tried adding ?? 0 but the compiler doesn't like that.
thanks for the help!
Enumerable.Count doesn't throw an error if the sequence is empty, it returns 0. Do you instead mean that dt can be null? So either the DataTable is null or one of the strings is null. You don't need to use String.Equals you can use == to compare strings meaningfully, then you don't get an exception. You can also use this shorter way using the overload of Count:
if(dt == null) return 0;
return dt.AsEnumerable()
.Count(x => x.Field<string>("names") == name && x.Field<string>("port") == "true");
Do this:
var count=dt != null ? dt.AsEnumerable().Where(x => x.Field<string>("names").Equals(name) && x.Field<string>("port").Equals("true")).Count() : 0;
It will simply check if dt is null before any operations on dt are executed.
Yoda comparison for handle case when you have null in database:
var count= dt.AsEnumerable()
.Where(x => name.Equals(x.Field<string>("names"))
&& "true".Equals(x.Field<string>("port")))
.Count();

Categories

Resources