How to handle out of bound exception inside Json object? - c#

I have a function that is returning a Json object as follows:
return Json(
db.Select(c => new GridViewModel()
{
Number = c.Rows[0][0].ToString(),
DocId = c.Rows[0][1].ToString(),
PartyName = c.Rows[0][2].ToString(),
FilingType = c.Rows[0][3].ToString(),
FilingDate = c.Rows[0][4].ToString(),
}
).ToDataSourceResult(request));
db is a DataTable object, currently I just have one row so I am using index=0. I keep getting error massage in vs saying "An exception of type 'System.IndexOutOfRangeException' occurred in System.Data.dll but was not handled in user code"
Is there a way how to add try catch inside a Json object?
Thanks

DataTable doesn't have .Select(Func<...>) method.
it has DataTable.Select(string filterExpression), so it is very similar what you have in SQL e.g.
Select * from MyTable WHERE Column1 = 'something'
for DataTable it will be
var myFilteredRows = myDataTable.Select("Column1 = 'something'")
Please visit MSDN for more info.
According to your code I assume you want to use LINQ Enumerable.Select on non-enumerable object. Which is impossible :)
So, if you have DataSet then you can do this
DataSet myDataSet = init from database
then
dataSet.Tables.Cast<System.Data.DataTable>().Select(table => new YourObject
{
init your object here, to get rows do this
MyRows = table.Rows.Cast<System.Data.DataRow>().Select(row => MyRowObject
{
init row object here
})
});
If you have only one DataTable (not DataSet)
then
table.Rows.Cast<System.Data.DataRow>().Select(row => GridViewModel
{
Number = row[0].ToString(),
DocId = row[1].ToString(),
PartyName = row[2].ToString(),
FilingType = row[3].ToString(),
FilingDate = row[4].ToString(),
});
Also I highly recommend to use column names and not indexes to avoid confusion in the future.
Hope this helps.

Related

How to delete first column in all datatables within a collection of datatables C#

I have need to check for the data returned from a Sybase query to check the first column which corresponds to which spreadsheet a given set of data will be displayed. I can get the data correctly in my dataset but the trouble comes when I try and remove the grouped column.
My sample data is as follows:
public static DataTable JustDataTableWithSheetColumn()
{
var sample = new DataTable();
sample.Columns.Add("SomethingSheet", typeof(string));
sample.Columns.Add("Column1", typeof(string));
sample.Columns.Add("Column2", typeof(string));
sample.Rows.Add("1", "Somestuff", "this other stuff");
sample.Rows.Add("1", "Fluffy", "this stuff");
sample.Rows.Add("2", "ToolShed", "this other stf");
sample.Rows.Add("2", "FudgeCycles", "this oer stuff");
sample.Rows.Add("2", "Crap", "thr stuff");
sample.Rows.Add("2", "stuff and stuff", "thiuff");
sample.Rows.Add("2", "test crap", "this stuff");
sample.Rows.Add("2", "dungheap", "this othuff");
sample.Rows.Add("3", "people eater", "this other stf");
sample.Rows.Add("3", "no purple people", "ths oth stff");
return sample;
}
And the following properly groups and applies them to datatables:
var thing = DataTableExamples.JustDataTableWithSheetColumn();
if (thing.Columns[0].ColumnName.Contains("Sheet"))
{
var test = from t in thing.AsEnumerable()
group t by t.ItemArray[0]
into g
select g.ToList().CopyToDataTable();
}
I have tried without the .CopyToDataTable() to just have a collection of DataRows and tried to query those using Skip(1) but I think my order of operations is incorrect or I am within that nebula I sometimes get lost in with IEnumerable vs IQueryable and all those variations.
Like so:
datarow.ItemArray.Skip(1).ToArray();
I have also tried to loop through the datatable collection and use dt.RemoveAt(0) but I am unable to reference the manipulated datatable (or incorrectly doing so).
foreach (var dt in test)
{
dt.Columns.RemoveAt(0);
}
Bottom line is that the first column on the data returned from the database doesn't need to be displayed or used once I translate them into datatables for later addition to the Dataset I return from this API.
So I am looking for an elegant way to get what I require with as little boxing and unboxing as possible. This part has to be done prior to adding it to the end Dataset because each of these weird stored procedures could potentially return a different datatable structure so I can't simply remove all of the first columns from the end dataset.
Thanks for your help.
dr.ItemArray.Skip(1).ToArray();
I suspect this (whatever dr is - it's not mentioned in your question) was used in the wrong place, and you ended up removing the column you wanted to group on, before the grouping was done
query those using Skip(1)
Skipping a datarow won't help you skip a column though - it just drops the first entire row of data
You can just drop the column after you prepare rather than getting into anything convoluted:
if (thing.Columns[0].ColumnName.Contains("Sheet"))
{
var test = from t in thing.AsEnumerable()
group t by t.ItemArray[0]
into g
select g.ToList().CopyToDataTable();
foreach(var dt in test){
dt.Columns.RemoveAt(0);
endDataSet.Tables.Add(dt);
}
}
Or you can manipulate the result dataset:
//referencing known table names
var dtToStrip = new[] { "ATableName", "BTableName" }
foreach(DataTable dt in endDataSet.Tables)
if(dtToStrip.Contains(dt.TableName))
dt.Columns.RemoveAt(0);
//or removing any column named sheet from any table in the set
foreach(DataTable dt in endDataSet.Tables)
if(dt.Columns.Count > 0 && dt.Columns[0].ColumName.Contains("Sheet"))
dt.Columns.RemoveAt(0);
I believe I am a victim of the deferred execution in this case.
Originally, I was doing the following:
if (thing.Columns[0].ColumnName.Contains("Sheet"))
{
var test = from t in thing.AsEnumerable()
group t by t.ItemArray[0]
into g
select g.ToList().CopyToDataTable();
foreach (var dt in test)
{
dt.Columns.RemoveAt(0);
}
ds.Tables.AddRange(test.ToArray());
}
Which I mistakenly assumed was executing the query upon doing the first .ToList(). But it didn't get executed until I did the .ToArray() when adding it to the DataSet at the end. Which, if I understand this correctly, means that the executions within my foreach were all for naught because they were independent executions.
If I instead move that .ToArray() to the LINQ query first it seems to work:
if (thing.Columns[0].ColumnName.Contains("Sheet"))
{
var test = (from t in thing.AsEnumerable()
group t by t.ItemArray[0]
into g
select g.ToList().CopyToDataTable()).ToArray();
foreach (var dt in test)
{
dt.Columns.RemoveAt(0);
}
ds.Tables.AddRange(test);
}
Thanks for the help.
Please let me know if my conclusions are incorrect or if I missed some logic as some point that would make this more helpful for other devs having a similar issue.

How to get Column Names using Linq from DataTable

I'm trying to use LINQ on DataTable that's getting it's data from sql. So I have a data table with it's usual columns and rows and it appears exactly like a sql select statement. Now I need to get certain rows and columns (including column names) from this data.
I converted the datatable to something LINQ can use using AsEnumerable but I'm not sure what exactly it does. Does it convert the data into an array of objects where each row becomes an object?
I'm used to working with Javascript and it's newer arrow functions so i'd like to use Linq with lambda to keep it consistent.
I'm trying to get rows and column names where first column has a value equal to 2018
DataTable myTable = getData(); // populates the datatable and I've verified the data
var linqTable = myTable.AsEnumerable().Select( x => x[0] = 2018);
I need to get the rows and column names. e.g like an object or array of objects.However, the code above doesn't return the data or column names but just two rows with 2018 in it.
My goal is to eventually serialize this data as json and send it to web page.
To Get the column names:
myTable.Columns.Cast<DataColumn>().Select(dc =>dc.ColumnName).ToList();
The problem is Select() is projecting the objects into a new form. You are seeing 2018 because of '=' instead of '=='. You need to use Where()
var linqTable = myTable.AsEnumerable().Where( x => x.Field<int>(0) == 2018);
You will still end up with a list of DataRows though. The DataTable object isn't really what you should be using because it already provides a nice way to filter its rows:
myTable.Rows.Find(2018);
If you are trying to convert it to a list of objects you should use the Select() method something like:
var linqTable = myTable.AsEnumerable().Where(x => x.Field<int>(0) == 2018)
.Select(x => new
{
year = x[0],
p1 = x[1],
p2 = x[2] // etc...
});
You can create the following function:
public static DataTable CreateDataTableFromAnyCollection<T>(IEnumerable<T> list)
{
Type type = typeof(T);
var properties = type.GetProperties();
DataTable dataTable = new DataTable();
foreach (PropertyInfo info in properties)
{
dataTable.Columns.Add(new DataColumn(info.Name, Nullable.GetUnderlyingType(info.PropertyType) ?? info.PropertyType));
}
foreach (T entity in list)
{
object[] values = new object[properties.Length];
for (int i = 0; i < properties.Length; i++)
{
values[i] = properties[i].GetValue(entity,null);
}
dataTable.Rows.Add(values);
}
return dataTable;
}
and pass any type of object your LINQ query returning.
DataTable dt = CreateDataTableFromAnyCollection(query);
I hope this will help you.
Creating a DataTable From a Query (LINQ to DataSet)

TableAdapter Query with optional WHERE paramerter

I am trying to create a TableAdapter query with an optional WHERE parameter.
This is my query:
SELECT Productos.Categoria, Productos.Subcategoria, Productos.Nombre,
Productos.Marca, Productos.Descripcion, Proveedores.Nombre AS Proveedor, Precios.Precio
FROM Precios, Productos, Proveedores
WHERE Precios.Producto_ID = Productos.ID AND Precios.Proveedor_ID =
Proveedores.ID AND Proveedores.Nombre = ?
I would like "Proveedores.Nombre = ?" to be optional or if ? = null or nothing, the query does not filter by Proveedores.Nombre
I have tried this:
(Proveedores.Nombre =#PNombre OR #PNombre = NULL)
But I have got an error:
Generated SELECT statement:
Error in WHERE clause near '#'.
Unable to parse the query text
Thank you very much for you help,
Regards
Andres
EDIT:
I ma in a windows form project. I am using a DataSource - DataSet linked to my access database. So to create FillBy() and GetData() I use a table-adapter which was automatically created when I inserted the DataSource to my WindowsForm.
This is the method created liked to the GetData() I am using:
public virtual DB_ProvProd2DataSet.ProductosDataTable GetDataByTodo(string Nombre) {
this.Adapter.SelectCommand = this.CommandCollection[5];
if ((Nombre == null)) {
throw new global::System.ArgumentNullException("Nombre");
}
else {
this.Adapter.SelectCommand.Parameters[0].Value = ((string)(Nombre));
}
DB_ProvProd2DataSet.ProductosDataTable dataTable = new DB_ProvProd2DataSet.ProductosDataTable();
this.Adapter.Fill(dataTable);
return dataTable;
}
Where this.CommandCollection[5] = the query and this.Adapter.SelectCommand.Parameters[0] is the input related to the '?' of the query.
I hope this helps!
Thanks!!!
Try assing it to a local variable:
string tmp= #PNombre
(Proveedores.Nomber==tmp || tmp == null)

New column is added automaticlly when filling datagridview

I'm using linq to filling my datagrid view with this method:
public List<HopDongCungCap> XemHopDong()
{
return QL.HopDongCungCaps.ToList();
}
and this is my
Result
My dbo.HopDongCungCap just has 1-4 column
but i dont know why it appears the 5th column
Note that dbo.NhaCungCap has a relationship with dbo.HopDongCungCap
Thank you for watching my question!
A solution would be to project the wanted results with Linq like this:
var result = QL.HopDongCungCaps.Select(x => new
{
MaHD = x.MaHD,
TenHD = x.TenHD,
ThoiHan = x.ThoiHan,
NCC = x.NCC
}).ToList();
Note that I leave 'NhaCungCap' out from the result.
This will create a anonymous type.
But you can create a classobject or DTO(Dummy Transfer Object) and project the result that object. and assign that to the datagridview. (.Select(x=> new YourClassDTO...)

C# SMO Select from Database

I have been racking my brain trying to figure out how to execute a SELECT from Table using SMO in C# and returning that value to a string item.
I have seen multiple posts of how I can run a SQL script from within C# which is not what I want to do. Here is the code I have so far
public static void GetDealerInfo()
{
Server databaseServer = new Server(dbServer);
try
{
databaseServer.ConnectionContext.LoginSecure = dbSecure;
databaseServer.ConnectionContext.Login = dbUser;
databaseServer.ConnectionContext.Password = dbPass;
databaseServer.ConnectionContext.Connect();
sDealerName = databaseServer.ConnectionContext.ExecuteWithResults("USE DATABASE Select DataValue from TABLE where KEYField = 'DealershipName'").ToString();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
finally
{
if (databaseServer.ConnectionContext.IsOpen)
{
databaseServer.ConnectionContext.Disconnect();
}
}
}
I also have a string called sDealerName which is where I want to pull, all I am getting is
sDealerName = System.Data.DataSet
Can anyone point me in the correct direction?
UPDATE:
Here is the code to get it going or at least what worked for me
try
{
databaseServer.ConnectionContext.LoginSecure = dbSecure;
databaseServer.ConnectionContext.Login = dbUser;
databaseServer.ConnectionContext.Password = dbPass;
databaseServer.ConnectionContext.DatabaseName = dbDatabase;
databaseServer.ConnectionContext.Connect();
DataSet dsName = databaseServer.ConnectionContext.ExecuteWithResults("Select DataValue from ABSetup where KEYField = 'DealershipName'");
sDealerName = dsName.Tables[0].Rows[0][0].ToString();
DataSet dsNum = databaseServer.ConnectionContext.ExecuteWithResults("Select DataValue from ABSetup where KEYField = 'ABOfficeCID'");
sDealerNumber = dsNum.Tables[0].Rows[0][0].ToString();
}
Change your code to:
DataSet ds = databaseServer.ConnectionContext.ExecuteWithResults("Select DataValue from TABLE where KEYField = 'DealershipName'");
The "USE DATABASE;", first, you may not need it. Second it, if you mean "USE MyDatabaseName;" , try it with a semi colon after the name.
More important to your question : then do a
Console.Writeline (ds.GetXml );
You'll then "see" the DataSet, the DataTable, the row inside the DataTable from which to "pluck" your scalar value.
string value = string.Empty;
if(null!=ds) {
if(null!=ds.Tables) {
if(ds.Tables.Count > 0) {
if(null!=ds.Tables[0].Rows) {
if(ds.Tables[0].Rows.Count > 0) {
if(null!=ds.Tables[0].Rows[0].Columns){
if(ds.Tables[0].Rows[0].Columns.Count > 0)
{
value = ds.Tables[0].Rows[0].Columns[0].Value;
}}}}}}}
"Count" may be "Length", I'm going from memory.
My code is untested from memory, so take it with a grain of salt.
You're calling ToString() on the object instance which is why you're getting the fullly qualified type name.
The value you're looking for will be inside a DataTable object within the DataSet. Run you're code again and break on the sDealerName line. Then using the magnifying glass tool click on that to open the dataset viewer and you'll be able to figure the rest out from there.

Categories