Linq auto converting string to single on comparison - c#

Im trying to do a simple string comparison in linq between two strings.
The strings are sizes and some of the sizes have a decimal within the string like "2.75". I get an error when comparing strings in the table against strings with decimals, saying "Unable to cast object of type 'System.Single' to type 'System.String'" Type checking within the debugger reveals that it is a string before the comparison. Why is this happening, and how can I make sure that strings with decimals inside get treated as strings?
var results = from item in _table.AsEnumerable()
where item.Field<string>("Width") == _size.Width &&
item.Field<string>("Length") == _size.Length
select item;

You need to convert the read values into singles:
var results = from item in _table.AsEnumerable()
where Convert.ToSingle(item.Field<string>("Width")) == _size.Width &&
Convert.ToSingle(item.Field<string>("Length")) == _size.Length
select item;
or
var results = from item in _table.AsEnumerable()
let width = Convert.ToSingle(item.Field<string>("Width"))
let length = Convert.ToSingle(item.Field<string>("Length"))
where (width == _size.Width) && (length == _size.Length)
select item;
to make it more readable

Related

using String.Split in a LINQ Where clause not working

I have below LINQ query:
List<string> paths = (from an in modelDb.MyTable
where an.Id == 0 &&
an.fileName.Split('_')[0] == "19292929383833abe838ac393" &&
an.fileName.Split('_')[1].ToUpper() == "FINANCE" &&
an.fileName.ToUpper().Contains("SIGNED")
select an.filePath).ToList();
... which is throwing below error on run-time:
Entity Framework 'ArrayIndex' is not supported in LINQ to Entities
fileName field in the LINQ query is a column in MyTable of string data type and contains strings like:
8845abd344ejk3444_FINANCE_SIGNED.pdf
4565abd34ryjk3454_FINANCE_UNSIGNED.pdf
477474jkedf34dfe4_MARKETING_UNSIGNED.pdf
and so on...
As stays in the message split will be not supported in the linq to sql and if you want to get result without additional methods, using Contains() should give you required result
List<string> paths = (from an in modelDb.MyTable
where an.Id == 0 &&
an.fileName.Contains("19292929383833abe838ac393") &&
an.fileName.Contains("FINANCE") &&
an.fileName.ToUpper().Contains("SIGNED")
select an.filePath).ToList();
Another way is to load all in memory and do split after that, e.g.
List<string> temp = (from an in modelDb.MyTable
where an.Id == 0
an.fileName.ToUpper().Contains("SIGNED")
select an.filePath).ToList();
paths = temp.Where(an =>
an.fileName.Split('_')[0] == "19292929383833abe838ac393" &&
an.fileName.Split('_')[1].ToUpper() == "FINANCE").ToList();

how to get a linq query result to int

below query return a single value eg 50. I want it be assign to int so I can do some calculation with that value. how can I do this
var LTLimit = from a in dbavailability.tACLicenseTypes
where a.License_Type == "Long Term"
select a.Limit;
string AST = "";
I'm not completely clear on what you're asking, but presumably the type of data returned by your Linq query is not int, and you want to convert it to int? If so, simply convert it to an int:
var LTLimit = (from a in dbavailability.tACLicenseTypes
where a.License_Type == "Long Term"
select a.Limit).ToList();
int LTLimitInt = 0
if (!int.TryParse(LTLimit.First(), out LTLimitInt))
{
Console.WritLine("LTLimit is not a number!")
}
Since you've updated your question, here's a solution to convert the returned number to an int, multiply it by 2, then convert the result to a string:
var LTLimit = (from a in dbavailability.tACLicenseTypes
where a.License_Type == "Long Term"
select a.Limit).ToList();
int LTLimitInt = 0;
string multipliedResultStr = string.Empty;
if (!int.TryParse(LTLimit.First(), out LTLimitInt))
{
Console.WritLine("LTLimit is not a number!")
}
else
{
multipliedResult = (LTLimitInt * 2).ToString();
Console.WriteLine(string.Format("Result is {0}, multipliedResult ));
}
Edit;
Corrected code to take first item from list.
The following code is one way to retrieve the first integer returned in your query:
var LTLimit = (from a in dbavailability.tACLicenseTypes
where a.License_Type == "Long Term"
select a.Limit).ToList();
int limit = LTLimit[0];
What is the return type of the query?
If the returned type is of another primative data type like a string, then you can try to convert it to an integer using :
var i = Convert.ToInt32(LTLimit);
Or using :
int.TryParse(LTLimit, out var i);
However, it would be better if the data was stored in the correct type in the first place.
You can use Sum() after where() for value of object property
like this bonus.Where(b => b.Id == x.key && b.RequiredScore.HasValue).Sum(b => b.RequiredScore.Value);

Convert. Int64 or int.Parse Is Not Recognized LINQ To Entities

I am trying to get range data between two strings.
i have list of string which have data like this
Example:
K123456,
H123456,
J123456,
T122123,
So the first charter of string object contains an alphabet.
var StartLabwareid = int.Parse(obj.LWbStartId.Replace(labIni,""));
var EndtLabwareid = int.Parse(obj.LWbEndId.Replace(labIni, ""));
var LabWId = (from ai in _entities.Ai
join result in _entities.Re on ai.Id equals re.Id
where (Convert.ToInt32(ai.Id.Replace(Ini,"")) <= Startid ||
Convert.ToInt32(ai.Id.Replace(Ini, "")) >= Endtid)
select new MViewModel
{
ID = re.Id,
}).ToList();
Or I can use something else to compare to string and get data between that as we do in date range St rating and Ending Date
You cannot use C# functions such as Convert in Linq to Entities. Instead, you could do your comparison after the result is materialized, or use SqlFunctions. With SqlFunctions, you should get your result with combining Stuff and CharIndex functions. Modify the line below to suit your needs, since you are not providing all of the code.
SqlFunctions.Stuff(ai.Id, SqlFunctions.CharIndex(ai.Id, "replaceable"), 3, "")

Casting String as DateTime in LINQ

I have a table with a following format.
PID ID Label Value
------------------------------------------
1 1 First Name Jenna
1 2 DOB 10/12/1980
I need to retrieve all PIDs where First name starting with J and Month of DOB is 10.
in my code, I retrieve these in DataTable in C# and then tried to use LINQ to retrieve the results I want. This is just an example. These Labels could be anything user defines.
using LINQ I am able to retrieve all PIDs where First Name start with J, but every time I tried to Cast Value for DOB I get cast not valid error. I cannot change the column type in the database since Value could contain any type of information.
Here's a piece of my code. I am new to LINQ, and still trying to figure out around it.
var resultQuery = from r in query.AsEnumerable()
where (r.Field<string>("Label") == Label &&
r.Field<DateTime>("Value").Month == 10)
select r.Field<int>("PID");
Since not all items in the Value column of the table are convertible to DateTime, what you have will fail on invalid conversions. You can add in a clause that first checks that the value is a DateTime and only if it is, converts it and checks the .Month property.
DateTime d;
var resultQuery = from r in query.AsEnumerable()
where (r.Field<string>("Label") == Label &&
DateTime.TryParse(r.Field<string>("Value"), out d) &&
d.Month == 10)
select r.Field<int>("PID");
To potentially improve readability, you could also extract this out into a separate method:
var resultQuery = from r in query.AsEnumerable()
let d = TryGetDate(r.Field<string>("Value"))
where (r.Field<string>("Label") == Label &&
d != null &&
d.Month == 10)
select r.Field<int>("PID");
private DateTime? TryGetDate(string value)
{
DateTime d;
return DateTime.TryParse(value, out d) ? d : default(DateTime?);
}
You are going to end up filtering in memory which isn't very efficient.
So first select your data
var data= from r in query.AsEnumerable();
Then filter on the data
var filtered = from item in data
where item.Label == "Label"
&& Convert.ToDateTime(item.DOB).Month == 10
select item.PID;

How to query a C# dictionary and return a specific set of values

I have a dictionary in my C# program that contains a list of Key + Values.
The values are itemid, Month, Year, Count
I would like to query the dictionary by comparing a set of values (itemid, Month, Year) and return true or false if a the specific itemid + Month + Year exist.
So if all 3 values (itemid + Month + Year) exist return true else return false.
I tried something like this
(if (myd.Select(d => d.Value.itemid == item.itemid && d.Value.Month == DateRange.Month && d.Value.Year == DateRange.Year).ToString() != "")
The above didn't work.
You seem to misunderstand the usage of the Select() method. Select creates a "projection"; given an input collection (enumerable) of elements, it produces an output enumerable that is equal in cardinality, but is composed of elements that are each the result of a transformation of the corresponding element of the input.
What you need is either a Where() method (which returns a list, lesser or equal in cardinality to the input, of the elements from the input for which a boolean condition is true), or an Any() method (which returns a single "true" or "false" if any of the elements in the input meet the condition):
if(myd.Where(d => d.Value.itemid == item.itemid
&& d.Value.Month == DateRange.Month
&& d.Value.Year == DateRange.Year).Count() >= 1)
...
//produces the equivalent result but generally performs faster
if(myd.Any(d => d.Value.itemid == item.itemid
&& d.Value.Month == DateRange.Month
&& d.Value.Year == DateRange.Year))
...
If like linq-Syntax, this checks if at least one item that satisfies all three condition exists:
if((from d in myd
where d.Value.itemid == item.itemid
&& d.Value.Month == DateRange.Month
&& d.Value.Year == DateRange.Year).FirstOrDefault() != null)
You'll need to create a 2nd dictionary if you want to do lookups with another key (in this case itemid,month,year, probably placed into a Tuple), and you'll need to maintain them both whenever you add/remove from either.
use Where to filter (I'm assuming the condition in your code is defined correctly... you haven't given us enough info to evaluate that)
var filteredDictionary = myd.Where(d => d.Value.itemid == item.itemid && d.Value.Month == DateRange.Month && d.Value.Year == DateRange.Year)
use Select to transform from a KeyValuePair to just a value
var filteredValues = filteredDictionary.Select(x=>x.Value)
use Any to return a bool of whether or not an item exists
bool matchExists = myd.Any(d => d.Value.itemid == item.itemid && d.Value.Month == DateRange.Month && d.Value.Year == DateRange.Year)
Any is going to be most efficient for the problem you describe because it will stop evaluating items in the dictionary and return True as soon as a match is found
If you are working with .NET 4.0 you can use Tuples as keys.
var dict = new Dictionary<Tuple<int,int,int>,MyValueType>();
You can then test if a value exists with
var key = new Tuple<int,int,int>(item.itemid, DateRange.Month, DateRange.Year);
if(dict.ContainsKey(key)) {
...
}
Or you can test
if(dict.ContainsValue(referenceValue)) {
...
}
You will have to pass it a reference value containing what you are looking for. Make sure that your value type implements EqualityComparer<T>.
The first method will be much faster, since the dictionary is accessed by the key. If you are not accessing the dictionary by the key, you could use a List<T> as well.

Categories