I'm trying to sort a column, but the value is stored as nvarchar in the database, how can I convert it to a double so it sorts here? I tried to do Convert.ToDouble(t.PressureChange), but it didn't work...
if (column == "PressureChange")
{
if (sortDirection == "ascending")
testResults = testResults.OrderBy(t => t.PressureChange);
else
testResults = testResults.OrderByDescending(t => t.PressureChange);
}
You could try
if (column == "PressureChange")
{
if (sortDirection == "ascending")
{
testResults = testResults.OrderBy(t => double.Parse(t.PressureChange));
}
else
{
testResults = testResults.OrderByDescending
(t => double.Parse(t.PressureChange));
}
}
... but it depends whether that method is supported by LINQ to SQL. To be honest, it sounds like you've got bigger problems in terms of your design: if you're trying to store a double value in the database, you shouldn't be using a varchar field to start with. Fix your schema if you possibly can.
EDIT: Note that based on the information on this page about LINQ to SQL and Convert.* it looks like Convert.ToDouble should work, so please give us more information about what happened when you tried it.
Rather use TryParse to avoid exceptions. In this code I used 0.0 as a default value if it could not parse the string.
double temp = 0.0;
if (column == "PressureChange")
{
if (sortDirection == "ascending")
testResults = testResults.OrderBy(t => (double.TryParse(t.PressureChange.toString(), out temp) ? temp : 0.0)).ToList();
else
testResults = testResults.OrderByDescending(t => (double.TryParse(t.PressureChange.toString(), out temp) ? temp : 0.0)).ToList();
}
I have not tested it but you can use an extension method like this:
public class StringRealComparer : IComparer<string>
{
public int Compare(string s1, string s2)
{
double d1;
double d2;
double.tryParse(s1, out d1);
double.TryParse(s2, out d2);
return double.Compare(d1, d2);
}
}
Related
Hi I have a linq query as below
var perChange = (from data in globalDS.Tables[0].AsEnumerable().AsParallel()
select data.Field<double>("PercentChange")).ToList();
Now the dataset globalDS contains null as well as varchar values in them. So there is an obvious type cast error that is generated. Is there a way to try.Parse the value in "Percentage Change" column and select only the valid fields.
DataRow.Field supports nullable types:
List<double> result = globalDS.Tables[0].AsEnumerable().AsParallel()
.Where(r => r.Field<double?>("PercentChange").HasValue)
.Select(r => r.Field<double?>("PercentChange").Value)
.ToList();
Edit: Since you have mentioned that the field contains strings instead of doubles:
List<double> result = globalDS.Tables[0].AsEnumerable().AsParallel()
.Select(r => r.Field<string>("PercentChange").TryGetDouble())
.Where(nullDouble => nullDouble.HasValue)
.Select(nullDouble => nullDouble.Value)
.ToList();
I've used this extension to try-parse a string to double? which is safer than parsing "on the fly" into the local variable, especially with AsParallel:
public static Double? TryGetDouble(this string item, IFormatProvider formatProvider = null)
{
if (formatProvider == null) formatProvider = NumberFormatInfo.CurrentInfo;
Double d = 0d;
bool success = Double.TryParse(item, NumberStyles.Any, formatProvider, out d);
if (success)
return d;
else
return null;
}
How about this:
double temp;
var perChange = (
from data in globalDS.Tables[0].AsEnumerable().AsParallel()
where !data.IsNull("PercentChange")
&& double.TryParse(data.Field<string>("PercentChange"), out temp)
select double.Parse(data.Field<string>("PercentChange"))
).ToList();
Try a select using a where clause in which you check the type. This would be something like: where x != null && TypeOf(x) == double
I am very new to programming and I can't seem to find a way around this. Maybe there is also a better way.
I am trying to get 2 values out of a single row in my database. I have connected to it using EF.
My code is:
using (var myEntities = new dataEntities())
{
var myValues = (from values in myEntities.PointValues
where values.PointID == dataValue && values.DataTime >= fromDate && values.DataTime <= toDate
select new
{ values.DataTime,
values.DataValue
}).ToList();
I then write them to a file with this code:
using (StreamWriter sw = new StreamWriter(#"c:\Test.csv"))
{
for (var i = 0; i < myValues.Count; i++)
{
sw.WriteLine(myValues[i]);
}
}
The problem is the resulting CSV file is like this:
{ DataTime = 1/20/2010 2:15:00 AM, DataValue = 11.72 }
How do I get rid of the { DataTime =, DataValue and the closing }? (DataTime and DataValue are the field labels in the database).
Many thanks for any assistance.
Kind regards,
Julian
You just need to change how you write out the information:
using (var sw = new StreamWriter(#"c:\Test.csv"))
{
foreach(var value in myValues)
{
sw.WriteLine(string.Format("{0}, {1}", value.DataTime, value.DataValue));
}
}
Right now, you're writing out the anonymous class directly, instead of creating the output formatted as needed.
Alternatively, you could build the string directly in your query and write the results easily using:
var myValues = (from values in myEntities.PointValues
where values.PointID == dataValue && values.DataTime >= fromDate && values.DataTime <= toDate
select new
{ values.DataTime,
values.DataValue
})
.AsEnumerable()
.Select(v => string.Format("{0}, {1}", v.DataTime, v.DataValue));
File.WriteAllLines(#"c:\Test.csv", myValues);
This would just build a IEnumerable<string> instead of building the anonymous class.
I would use this approach if you're not using the query results for anything other than writing to the file. If you're using the anonymous class in other code in between, the first is going to keep you from needing to change that code.
Add another select at the end.
var myValues = (from values in myEntities.PointValues
where values.PointID == dataValue
&& values.DataTime >= fromDate
&& values.DataTime <= toDate
select new
{ values.DataTime,
values.DataValue
})
.ToList()
.Select(x => string.Format("{0}, {1}", x.DateTime, x.DataValue);
Additionally, if you don't need bells & whistles of the StreamWriter you could also use File.WriteAllLines():
File.WriteAllLines(#"c:\Test.csv", myValues);
(updated per Reed's post)
Is there a better way to check if a LINQ projection query returns results:
IList<T> TList = db.Ts.Where(x => x.TId == 1).ToList(); // More canonical way for this?
if (TitleList.Count > 0)
{
// Result returned non-zero list!
string s = TList.Name;
}
You can use Any(), or perhaps more appropriately to your example, SingleOrDefault(). Note that if you are expecting more than one result and plan to use all of them, then it doesn't really save anything to use Any() instead of converting to a List and checking the length. If you don't plan to use all the results or you're building a larger query that might change how the query is performed then it can be a reasonable alternative.
var item = db.Ts.SingleOrDefault( x => x.TId == 1 );
if (item != null)
{
string s = item.Name;
...
}
or
var query = db.Ts.Where( x => x.Prop == "foo" );
if (query.Any())
{
var moreComplexQuery = query.Join( db.Xs, t => t.TId, x => x.TId );
...
}
I get some data about customers in my database with this method:
public List<KlientViewModel> GetListOfKlientViewModel()
{
List<KlientViewModel> list = _klientRepository.List().Select(k => new KlientViewModel
{
Id = k.Id,
Imie = k.Imie,
Nazwisko = k.Nazwisko,
Nazwa = k.Nazwa,
SposobPlatnosci = k.SposobPlatnosci,
}).ToList();
return list;
}
but also I have another method which counts value for extra field in KlientViewModel - field called 'Naleznosci'.
I have another method which counts value for this field based on customers ids, it looks like this:
public Dictionary<int, decimal> GetNaleznosc(List<int> klientIds)
{
return klientIds.ToDictionary(klientId => klientId, klientId => (from z in _zdarzenieRepository.List()
from c in z.Klient.Cennik
where z.TypZdarzenia == (int) TypyZdarzen.Sprzedaz && z.IdTowar == c.IdTowar && z.Sprzedaz.Data >= c.Od && (z.Sprzedaz.Data < c.Do || c.Do == null) && z.Klient.Id == klientId
select z.Ilosc*(z.Kwota > 0 ? z.Kwota : c.Cena)).Sum() ?? 0);
}
So what I want to do is to join data from method GetNaleznosc with data generated in method GetListOfKlientViewModel. I call GetNaleznosc like this:
GetNaleznosc(list.Select(k => k.Id).ToList())
but don't know what to do next.
Having obtained the dictionary:
var dict = GetNaleznosc(list.Select(k => k.Id).ToList());
You can now efficiently look up the decimal value of Naleznosci for a given client:
foreach (var k in list)
k.Naleznosci = dict[k.Id];
Now you have merged the values into the main list. Is this what you mean?
By the way, in your function that builds the dictionary, you make it accept a List<int>, but then all you do is call ToDictionary on it, which only requires IEnumerable<int>. So change the parameter type to that, and then you can call it:
var dict = GetNaleznosc(list.Select(k => k.Id));
This removes the call to ToList, which avoids making an unnecessary intermediate copy of the whole list of Ids. Probably won't make much difference in this case if you're hitting a database and then building up a large set of results in memory, but maybe worth bearing in mind for other uses of these operations.
Also, looking again at the helper function, there is no apparent advantage in building up the set of results in a dictionary for a list of ids, because each one is handled independently. You could simply put:
public decimal GetNaleznosc(int klientId)
{
return (from z in _zdarzenieRepository.List()
from c in z.Klient.Cennik
where z.TypZdarzenia == (int) TypyZdarzen.Sprzedaz && z.IdTowar == c.IdTowar && z.Sprzedaz.Data >= c.Od && (z.Sprzedaz.Data < c.Do || c.Do == null) && z.Klient.Id == klientId
select z.Ilosc*(z.Kwota > 0 ? z.Kwota : c.Cena)).Sum() ?? 0);
}
That is, provide a function that discovers just one value. Now you can directly build the right list:
public List<KlientViewModel> GetListOfKlientViewModel()
{
return _klientRepository.List().AsEnumerable().Select(k => new KlientViewModel
{
Id = k.Id,
Imie = k.Imie,
Nazwisko = k.Nazwisko,
Nazwa = k.Nazwa,
SposobPlatnosci = k.SposobPlatnosci,
Naleznosci = GetNaleznosc(k.Id)
}).ToList();
}
Let's say I have an array, and I want to do a LINQ query against a varchar that returns any records that have an element of the array anywhere in the varchar.
Something like this would be sweet.
string[] industries = { "airline", "railroad" }
var query = from c in contacts where c.industry.LikeAnyElement(industries) select c
Any ideas?
This is actually an example I use in my "Express Yourself" presentation, for something that is hard to do in regular LINQ; As far as I know, the easiest way to do this is by writing the predicate manually. I use the example below (note it would work equally for StartsWith etc):
using (var ctx = new NorthwindDataContext())
{
ctx.Log = Console.Out;
var data = ctx.Customers.WhereTrueForAny(
s => cust => cust.CompanyName.Contains(s),
"a", "de", "s").ToArray();
}
// ...
public static class QueryableExt
{
public static IQueryable<TSource> WhereTrueForAny<TSource, TValue>(
this IQueryable<TSource> source,
Func<TValue, Expression<Func<TSource, bool>>> selector,
params TValue[] values)
{
return source.Where(BuildTrueForAny(selector, values));
}
public static Expression<Func<TSource, bool>> BuildTrueForAny<TSource, TValue>(
Func<TValue, Expression<Func<TSource, bool>>> selector,
params TValue[] values)
{
if (selector == null) throw new ArgumentNullException("selector");
if (values == null) throw new ArgumentNullException("values");
if (values.Length == 0) return x => true;
if (values.Length == 1) return selector(values[0]);
var param = Expression.Parameter(typeof(TSource), "x");
Expression body = Expression.Invoke(selector(values[0]), param);
for (int i = 1; i < values.Length; i++)
{
body = Expression.OrElse(body,
Expression.Invoke(selector(values[i]), param));
}
return Expression.Lambda<Func<TSource, bool>>(body, param);
}
}
from c in contracts
where industries.Any(i => i == c.industry)
select c;
something like that. use the any method on the collection.
IEnumerable.Contains() translates to SQL IN as in:
WHERE 'american airlines' IN ('airline', 'railroad') -- FALSE
String.Contains() which translates to SQL LIKE %...% as in:
WHERE 'american airlines' LIKE '%airline%' -- TRUE
If you want the contacts where the contact's industry is LIKE (contains) any of the given industries, you want to combine both Any() and String.Contains() into something like this:
string[] industries = { "airline", "railroad" };
var query = from c in contacts
where industries.Any(i => c.Industry.Contains(i))
select c;
However, combining both Any() and String.Contains() like this is NOT supported in LINQ to SQL. If the set of given industries is small, you can try something like:
where c.Industry.Contains("airline") ||
c.Industry.Contains("railroad") || ...
Or (although normally not recommended) if the set of contacts is small enough, you could bring them all from the DB and apply the filter with LINQ to Objects by using contacts.AsEnumerable() or contacts.ToList() as the source of the query above:
var query = from c in contacts.AsEnumerable()
where industries.Any(i => c.Industry.Contains(i))
select c;
it will work if you build up the query as follows:
var query = from c in contacts.AsEnumerable()
select c;
query = query.Where(c=> (c.Industry.Contains("airline")) || (c.Industry.Contains("railroad")));
you just need to programmatically generate the string above if the parameters airline and railroad are user inputs. This was in fact a little more complicated than I was expecting. See article - http://www.albahari.com/nutshell/predicatebuilder.aspx
Unfortunately, LIKE is not supported in LINQ to SQL as per here:
http://msdn.microsoft.com/en-us/library/bb882677.aspx
To get around this, you will have to write a stored procedure which will accept the parameters you want to use in the like statement(s) and then call that from LINQ to SQL.
It should be noted that a few of the answers suggest using Contains. This won't work because it looks to see that the entire string matches the array element. What is being looked for is for the array element to be contained in the field itself, something like:
industry LIKE '%<element>%'
As Clark has mentioned in a comment, you could use a call to IndexOf on each element (which should translate to a SQL call):
string[] industries = { "airline", "railroad" }
var query =
from c in contacts
where
c.industry.IndexOf(industries[0]) != -1 ||
c.industry.IndexOf(industries[1]) != -1
If you know the length of the array and the number of elements, then you could hard-code this. If you don't, then you will have to create the Expression instance based on the array and the field you are looking at.