"Invalid Cast" In Linq - c#

I'm trying to filter a datatable with following code
private void Filter(string text)
{
int outText=0;
if (Int32.TryParse(text, out outText))
{
text = string.Empty;
}
DataTable DT = new DataTable();
DT = PinCDAO.GetArea().AsEnumerable().Where(r => r.Field<int>("AreaID")==Convert.ToInt32(outText) || (r.Field<string>("AreaDescription").Contains(text))).AsDataView().ToTable();
}
I'm getting the error "Specified cast is not valid".because of the code
r => r.Field<int>("AreaID")==Convert.ToInt32(outText)
I'm sure about that AreaID column Contains Integers
plz help me to solve this.

Try out code - Handle null in you code
because "AreaID" is nullable field.
DT = PinCDAO.GetArea().AsEnumerable().Where(r =>
(Convert.IsDBNull(r["AreaID"]) ? 0 : Convert.ToInt32(r["AreaID"])) ==outText
|| (r.Field<string>("AreaDescription").Contains(text))).AsDataView().ToTable();
this code handles null value easily..
already answered question by me : "Specified cast is not valid" error in LINQ's orderby clause

Variables passed as an out arguments need not be initialized prior to being passed. Moreover, outtext need not to be convert to Int32 as it is one already.
private void Filter(string text) {
int outText;
if (Int32.TryParse(text, out outText))
{
// text was integer and parsed successfully.
text = string.Empty;
}
DataTable DT = new DataTable();
DT = PinCDAO.GetArea().AsEnumerable().Where(r => r.Field<int>("AreaID")== outText || (r.Field<string>("AreaDescription").Contains(text))).AsDataView().ToTable(); }

Remove Convert.ToInt32, outText is already parsed as int using if (Int32.TryParse(text, out outText))
DT = PinCDAO.GetArea().AsEnumerable()
.Where(r => r.Field<int>("AreaID")==outText
|| (r.Field<string>("AreaDescription")
.Contains(text))).AsDataView().ToTable();
The reason you are getting the exception could be that "AreaID" may not contain an int value

You don't need conversion to int as outText already declared to int....You can simply use the outText in following way:
r => r.Field<int>("AreaID")==outText
You can change the expresson in following way:
r => Convert.ToInt32(r["AreaID"])==outText

Related

getting error while calculating the sum of the datatable column in C# [duplicate]

I have a data table and a column contains int values. I have not specified the column with any datatype. When I perform the following.
object sum = dttest.Compute("sum(Value)", "");
I am getting below error.
Invalid usage of aggregate function Sum() and Type: String.
And I tried converting column value to int using
object sum = dttest.Compute("sum(Convert(Value, 'System.Int32'))","");
again I am getting another error
Syntax error in aggregate argument: Expecting a single column argument
with possible 'Child' qualifier.
When I specify the datatype for the column, first code will return correct value. But in my case I can't specify column datatype. Any one having solution ?
You can use LINQ to Datatable:
var result = dttest.AsEnumerable()
.Sum(x => Convert.ToInt32(x["Value"]));
Example how to Sum for specific name:
var result = dttest.AsEnumerable()
.Where(r => r.Field<string>("Name") == "FilterName")
.Sum(x => Convert.ToInt32(x["Value"]));
try
object sum = dttest.Compute("Sum(Value)", "[Value] IS NOT NULL");
Sample code
static DataTable GetTable()
{
DataTable table = new DataTable();
table.Columns.Add("Value", typeof(int));
table.Columns.Add("Name", typeof(string));
table.Rows.Add(null, "a");
table.Rows.Add(50, "a");
table.Rows.Add(10, "a");
table.Rows.Add(21, "b");
table.Rows.Add(100, "b");
return table;
}
static void Main(string[] args)
{
DataTable dt =GetTable();
var str = dt.Compute("Sum(Value)", "Name='a' and Value is not null");
}
You can't Call Sum with Convert, but you can try below
DataTable dt =GetTable();
dt.Columns.Add("temp", typeof(int), "Convert(Value, 'System.Int32')");
var str = dt.Compute("Sum(temp)", "Name='a' and Value is not null");
try
dttest.Compute("Sum(Convert([Value], 'System.Int32'))","[Value] IS NOT NULL");
When the program try it sum a datatable column which declared as string this error occur.
Use the below code to make compute operation on string column.
dtTable.Compute("Sum(Convert(" + col_Name + ", 'System.Int32')","");

ValueMember from ComboBox to int

i have valueMember in combobox and i need to save this value to integer...
This is my code:
public class Benzinky
{
public int B_cislo { get; set; }
public string Benzinka { get; set; }
}
var lines = File.ReadAllLines(#"C:...\pokus.txt");
var data = lines.Select(l => l.Split());
List<Benzinky> allB = data.Where(arr => arr.Length >= 2
&& arr[1].Trim().All(Char.IsDigit))
.Select(arr =>
new Benzinky
{
Benzinka = arr[0].Trim(),
B_cislo = int.Parse(arr[1].Trim())
})
.ToList();
var bindingSourceB = new BindingSource();
bindingSourceB.DataSource = allB;
comboBox1.DataSource = bindingSourceB;
comboBox1.ValueMember = "B_cislo";
comboBox1.DisplayMember = "Benzinka";
my txt:
Prague 3106
Berlin 3107
........
Have you any ideas?
You should convert the valueMember of comboBox1 to an integer and put the result in Number. This can be done in multiple ways, you can use Convert.ToInt32();
But I would take a look at Int32.Parse() and Int32.TryParse()
Int32.Parse
Number = Int32.Parse(comboBox1.ValueMember);
Above code should do the trick, but you will run in to troubles when the string doesn't contain a value that can be parsed to an integer, an exception will be thrown.
You could use Int32.TryParse if you would like to get a bool value in return instead of an exception.
Int32.TryParse
int Number;
bool result = Int32.TryParse(comboBox1.ValueMember, out Number);
if (result)
{
Console.WriteLine("Converted '{0}' to {1}.", comboBox1.ValueMember, Number);
}
else
{
//conversion failed
//Int32.Parse, would throw a formatexception here.
}
Could you try following code:
comboBox1.DataSource = bindingSourceB;
comboBox1.ValueMember = "B_cislo";
comboBox1.DisplayMember = "Benzinka";
int Number;
if(Int32.TryParse(comboBox1.ValueMember, out Number))
{
//Conversion succeeded
}
else
{
//Conversion failed, you should send a message to the user
//Or fill Number with a default value, your choice.
}
Sources:
MSDN Int32.Parse
MSDN Int32.TryParse
ValueMember is just used to determine the value of your combobox SelectedValue. To get the valueMember part of your ComboBox item, you have to cast the underlying item (which is of type Benzinky in your example) to the correct type and get the desired value from some property, here is how it should be done if you know the underlying data type and valueMember beforehand:
int x = ((Benzinky) comboBox1.Items[index]).B_cislo;
//or using dynamic
dynamic item = comboBox1.Items[index];
int x = item.B_cislo;
However if you want something dynamic (that happen when the valueMember may change prorammatically at some time), you have to use Reflection like this:
object item = comboBox1.Items[index];
var x = (int) item.GetType().GetProperty(comboBox1.ValueMember)
.GetValue(item, null);
NOTE: However the Reflection approach is applicable only when the DataSource of your comboBox is not some class like DataTable, because a DataTable exposes its Column name as ValueMember not any properties of it, the underlying item will be a DataRowView and so in that case the reflection code will fail.

Invalid usage of aggregate function Sum() and Type: String

I have a data table and a column contains int values. I have not specified the column with any datatype. When I perform the following.
object sum = dttest.Compute("sum(Value)", "");
I am getting below error.
Invalid usage of aggregate function Sum() and Type: String.
And I tried converting column value to int using
object sum = dttest.Compute("sum(Convert(Value, 'System.Int32'))","");
again I am getting another error
Syntax error in aggregate argument: Expecting a single column argument
with possible 'Child' qualifier.
When I specify the datatype for the column, first code will return correct value. But in my case I can't specify column datatype. Any one having solution ?
You can use LINQ to Datatable:
var result = dttest.AsEnumerable()
.Sum(x => Convert.ToInt32(x["Value"]));
Example how to Sum for specific name:
var result = dttest.AsEnumerable()
.Where(r => r.Field<string>("Name") == "FilterName")
.Sum(x => Convert.ToInt32(x["Value"]));
try
object sum = dttest.Compute("Sum(Value)", "[Value] IS NOT NULL");
Sample code
static DataTable GetTable()
{
DataTable table = new DataTable();
table.Columns.Add("Value", typeof(int));
table.Columns.Add("Name", typeof(string));
table.Rows.Add(null, "a");
table.Rows.Add(50, "a");
table.Rows.Add(10, "a");
table.Rows.Add(21, "b");
table.Rows.Add(100, "b");
return table;
}
static void Main(string[] args)
{
DataTable dt =GetTable();
var str = dt.Compute("Sum(Value)", "Name='a' and Value is not null");
}
You can't Call Sum with Convert, but you can try below
DataTable dt =GetTable();
dt.Columns.Add("temp", typeof(int), "Convert(Value, 'System.Int32')");
var str = dt.Compute("Sum(temp)", "Name='a' and Value is not null");
try
dttest.Compute("Sum(Convert([Value], 'System.Int32'))","[Value] IS NOT NULL");
When the program try it sum a datatable column which declared as string this error occur.
Use the below code to make compute operation on string column.
dtTable.Compute("Sum(Convert(" + col_Name + ", 'System.Int32')","");

how to subtract two datatables with linq

Is there any way to subtract two datatables in order to have rows of the first datatable that are not in the second one?
I have tried .Except() method like below but it does not work for me.
dt1.AsEnumerable().Except(dt2.AsEnumerable()).CopyToDataTable();
I think i have mistake in using this method but i could not find that?
You can create your own Comparer using IEquailtyComparer
public class CustomDataRowComparer : IEqualityComparer<DataRow>
{
public bool Equals(DataRow x, DataRow y)
{
for (int i = 0; i < x.Table.Columns.Count; i++)
{
if (x[i].ToString() != y[i].ToString())
{
return false;
}
}
return true;
}
public int GetHashCode(DataRow obj)
{
return obj.ToString().GetHashCode();
}
}
Later you can call it like:
CustomDataRowComparer myDRComparer = new CustomDataRowComparer();
var result2 = dt1.AsEnumerable().Except(dt2.AsEnumerable(),myDRComparer).CopyToDataTable();
Except will not work because the references are different. Each "copy" of a data row in memory is a different object, thus the equality comparison being made in Except will always return false.
You need to compare with something comparable, like row IDs. A couple ideas how to do this:
var rowsInFirstNotInSecond = dt1.Rows.Where(r1=>!dt2.Rows.Any(r2=>r1.ID == r2.ID));
Or:
var rowsInFirstNotInSecond = dt1.Rows.Where(r1=>dt2.FindById(r1.ID) == null);
I have used the following code to subtract two datatables from each other :
var query =
from row1 in dt1
where !(from row2 in dt2
select row2.ID)
.Contains(row1.ID)
select row1;
this code returns exactly what i want...
This Code works for sure:
var rows =dtFirst.AsEnumerable().Except(dtSecond.AsEnumerable(), DataRowComparer.Default);
DataTable result = null;
if (rows.Count() != 0)
result = rows.CopyToDataTable();

Best way to get a single value from a DataTable?

I have a number of static classes that contain tables like this:
using System;
using System.Data;
using System.Globalization;
public static class TableFoo
{
private static readonly DataTable ItemTable;
static TableFoo()
{
ItemTable = new DataTable("TableFoo") { Locale = CultureInfo.InvariantCulture };
ItemTable.Columns.Add("Id", typeof(int));
ItemTable.Columns["Id"].Unique = true;
ItemTable.Columns.Add("Description", typeof(string));
ItemTable.Columns.Add("Data1", typeof(int));
ItemTable.Columns.Add("Data2", typeof(double));
ItemTable.Rows.Add(0, "Item 1", 1, 1.0);
ItemTable.Rows.Add(1, "Item 2", 1, 1.0);
ItemTable.Rows.Add(2, "Item 3", 2, 0.75);
ItemTable.Rows.Add(3, "Item 4", 4, 0.25);
ItemTable.Rows.Add(4, "Item 5", 1, 1.0);
}
public static DataTable GetItemTable()
{
return ItemTable;
}
public static int Data1(int id)
{
DataRow[] dr = ItemTable.Select("Id = " + id);
if (dr.Length == 0)
{
throw new ArgumentOutOfRangeException("id", "Out of range.");
}
return (int)dr[0]["Data1"];
}
public static double Data2(int id)
{
DataRow[] dr = ItemTable.Select("Id = " + id);
if (dr.Length == 0)
{
throw new ArgumentOutOfRangeException("id", "Out of range.");
}
return (double)dr[0]["Data2"];
}
}
Is there a better way of writing the Data1 or Data2 methods that return a single value from a single row that matches the given id?
Update #1:
I have created an extension method that seems quite nice:
public static T FirstValue<T>(this DataTable datatable, int id, string fieldName)
{
try
{
return datatable.Rows.OfType<DataRow>().Where(row => (int)row["Id"] == id).Select(row => (T)row[fieldName]).First();
}
catch
{
throw new ArgumentOutOfRangeException("id", "Out of range.");
}
}
My Data1 method then becomes:
public static int Data1(int id)
{
return ItemTable.FirstValue<int>(id, "Data1");
}
and Data2 becomes:
public static double Data2(int id)
{
return ItemTable.FirstValue<double>(id, "Data2");
}
Thanks to all your responses but especially to Anthony Pegram who gave the very nice single line of LINQ & Lambda code.
Have you considered using Linq (to DataSets)? With Linq expressions you wouldn't need those Data1 and Data2 functions at all since the lookup and filtering could happen in a single line of code.
Example added:
Shooting from the hip here, so please take it with a grain of salt (not near an IDE:)
DataTable itemTbl = GetItemTable().AsEnumerable();
double dt1 = ((From t In itemTbl Where t.Id = <your_id> Select t).First())["Data1"];
That's two lines of code but you could easily wrap the getting of the Enumerable.
I'm a little suspicious of your architecture, but never mind that. If you want a function that returns the first value of the first row of a datatable that it will get somehow, and you want it strongly typed, I think the function below will be an improvement. It would allow you to have just one function, reusable for different types. To use it you would have lines of code like:
int intValue = TableFoo.FirstValueOrDefault<int32>(7);
decimal decValue = TableFoo.FirstValueOrDefault<decimal>(7);
and if you feel like it:
string strValue = TableFoo.FirstValueOrDefault<string>(7);
int? nintValue = TableFoo.FirstValueOrDefault<int?>(7);
The function handles any type you generically give it, strings, other value types, nullable types, reference types. If the field is null, the function returns the "default" value for that type ("" for string). If it absolutely can't do the conversion, because you asked for an impossible conversion, it will throw an error. I've made it an extension method on the datarow type (called ValueOrDefault), and this sucker is really handy.
I adapted this data-tool extension method of mine for your situation. I'm in a VB shop, and I just don't have time to re-write the whole thing in C#, but you could do that easily enough.
Public Shared Function FirstValueOrDefault(Of T) (ByVal Int ID) As T
Dim r as datarow = ItemTable.Select("Id = " + id.ToString());
If r.IsNull(0) Then
If GetType(T) Is GetType(String) Then
Return CType(CType("", Object), T)
Else
Return Nothing
End If
Else
Try
Return r.Field(Of T)(0)
Catch ex As Exception
Return CType(r.Item(0), T)
End Try
End If
End Function

Categories

Resources