Update Row using SqlDataAdapter not working - c#

I wrote this function for updating one single row (I store the information in a class T):
public void Update(T model)
{
if (!Exist(model))
{
throw new Exception("Object Not Found");
}
DataRow row = Convert(model);
row.Table.Rows.Add(row);
row.AcceptChanges();
row.SetModified();
_dataAdapter.Update(new[] { row });
}
(The DataRow comes detached)
the SqlDataAdapter is configured as so:
SqlDataAdapter da = new SqlDataAdapter("Select * From " + tableName,
ConnectedDAL.GetConnection());
SqlCommandBuilder builder = new SqlCommandBuilder(da);
da.MissingSchemaAction = MissingSchemaAction.AddWithKey;
For some reason my insert and delete work, but the update does not.
The call to Update() completes without errors but the database does not receive the updates.
Help?
Update
The update command text from the command builder is wierd:
For cities (CityID, CityName, CountryID)
"Update [Cities] Set [CityName] = #p1, [CountryID] = #p2 WHERE (([CityID] = #p3 AND ([CityName] = #p4) AND ([CountryID] = #p5))
The first condition makes sense but the rest don't. Also the call returns 1, meaning the it thinks it made the changes.

I have a way to make it work.
public void Update(T model)
{
if (!Exist(model))
{
throw new Exception("Object Not Found");
}
DataRow tmp = GetRow(model);
_dataAdapter.Update(new []{ tmp });
}
private DataRow GetRow(T model)
{
DataRow row = Convert(model);
var schem = Schema;
string[] keys = new string[schem.PrimaryKey.Length];
for (var i = 0; i < schem.PrimaryKey.Length; i++)
{
DataColumn column = schem.PrimaryKey[i];
keys[i] = row[column.ColumnName].ToString();
}
DataRow dr = Convert(Select(keys));
dr.Table.Rows.Add(dr);
dr.AcceptChanges();
for (var i = 0; i < row.ItemArray.Length; i++)
{
if (!schem.Columns[i].AutoIncrement)
{
dr[i] = row.ItemArray[i];
}
}
return dr;
}
This works.

Related

How do you get a sqlite table schema using a query in c#

I have been searching high and low, using many methods to get a table schema from a table in sqlite. Please forgive me if this has been posted somewhere else.
Current query is
SELECT TOP (0) * FROM 'TableName'
but this returns nothing.
SELECT * FROM 'TableName'
also returns nothing if the table is empty.
I also used SQLiteConnection.GetSchema() but it doesn't return the table in question; it returns a table with other columns.
DataTable dtReturnTable = new DataTable();
sqlitecon.Open();
string[] sParameters = new string[4];
sParameters[2] = sTableName;
dtReturnTable = sqlitecon.GetSchema("Columns", sParameters);
sqlitecon.Close();
So what I did was this
private DataTable GetSQLiteTableWithQuery(string sQuery)
{
SQLiteConnection sqlconlocal = new SQLiteConnection(sSQLITEconnstring);
DataTable dtReturnTable = new DataTable();
SQLiteCommand sqliteCommand = new SQLiteCommand(sQuery, sqlconlocal);
using (sqlconlocal)
{
try
{
sqlconlocal.Open();
SQLiteDataReader sqliteReader = sqliteCommand.ExecuteReader();
if (sqliteReader.HasRows)
{
for (int i = 0; i < sqliteReader.FieldCount; i++)
{
dtReturnTable.Columns.Add(new DataColumn(sqliteReader.GetName(i)));
}
}
int j = 0;
while (sqliteReader.Read())
{
DataRow dtRow = dtReturnTable.NewRow();
dtReturnTable.Rows.Add(dtRow);
for (int i = 0; i < sqliteReader.FieldCount; i++)
{
dtReturnTable.Rows[j][i] = (sqliteReader.GetValue(i));
}
j++;
}
sqlconlocal.Close();
}
catch (SQLiteException e)
{
sqlconlocal.Close();
}
}
return dtReturnTable;
}
public DataTable GetSQLiteSchema(string sTableName)
{
string sQuery = "PRAGMA table_info('" + sTableName + "')";
DataTable dtWorking = GetSqLiteTableBasedOnQuery(sQuery);
DataTable dtReturn = new DataTable();
foreach (DataRow dr1 in dtWorking.Rows)
{
string sColName = dr1[1].ToString();
string sColtype = dr1[2].ToString();
if (sColtype.ToLower().Contains("nvarchar"))
{
dtReturn.Columns.Add(sColName, typeof(string));
}
else if (sColtype.ToLower().Contains("decimal"))
{
dtReturn.Columns.Add(sColName, typeof(decimal));
}
else if (sColtype.ToLower().Contains("int"))
{
dtReturn.Columns.Add(sColName, typeof(int));
}
else if (sColtype.ToLower().Contains("date"))
{
dtReturn.Columns.Add(sColName, typeof(DateTime));
}
else if (sColtype.ToLower().Contains("bit"))
{
dtReturn.Columns.Add(sColName, typeof(bool));
}
}
return dtReturn;
}

Entity Framework 6 and DBContext or DBQuery or DBSet or ObjectQuery with scalar variable

I'm trying to pass a variable to my DBContext extension. It works fine with a fixed string but when I try to use a variable I get the error "Must declare the scalar variable #p_linq_0"
var pn = "6-10064-01";
// put query results into datatable
var query = db.SWD_0004.Where(p => p.Part_Number == pn) as DbQuery<SWD_0004>;
var numResults = query.Count();
DataTable dt = db.DataTable(query.ToString());
// gets column names and put into array
List<DataRow> list = dt.AsEnumerable().ToList();
string[] columnList = dt.Columns.Cast<DataColumn>()
.Select(x => x.ColumnName)
.ToArray();
var rowCount = dt.Rows.Count;
var columnCount = dt.Columns.Count;
for (var j = 0; j < rowCount; j++)
{
for (var i = 1; i < columnCount; i++) // skip ID column
{
var columnName = columnList[i];
var data = list[j][i].ToString();
lstName.Items.Add(columnName);
lstData.Items.Add(data);
}
}
public static class DbContextExtensions
{
public static DataTable DataTable(this DbContext context, string query)
{
DbProviderFactory dbFactory = DbProviderFactories.GetFactory(context.Database.Connection);
using (var cmd = dbFactory.CreateCommand())
{
cmd.Connection = context.Database.Connection;
cmd.CommandType = CommandType.Text;
cmd.CommandText = query;
using (DbDataAdapter adapter = dbFactory.CreateDataAdapter())
{
adapter.SelectCommand = cmd;
DataTable dt = new DataTable();
adapter.Fill(dt);
return dt;
}
}
}
}
I've tried a few conversion methods to ObjectQuery, DBQuery, etc with no result. I'm so confused need some direction please.
I finally found the answer I was looking for!
https://www.c-sharpcorner.com/UploadFile/0c1bb2/convert-linq-query-result-to-datatable/

Create dynamic buttons while reading from SQL Server

I'm using this code while reading from SQL Server. The problem is that it runs the loop as many times are my SQL Server results.
SqlCommand sqlCmd = new SqlCommand("Select Name from TablesDesigner", con);
SqlDataReader sqlReader = sqlCmd.ExecuteReader();
while (sqlReader.Read())
{
for (int row = 0; row < NUM_ROWS; row++)
{
TableRow tablerow = new TableRow(this);
TableLayout.LayoutParams linearLayoutParams = new TableLayout.LayoutParams(TableLayout.LayoutParams.MatchParent, TableLayout.LayoutParams.MatchParent, 1.0f);
tablerow.LayoutParameters = linearLayoutParams;
table.AddView(tablerow);
for (int col = 0; col < NUM_COLS; col++)
{
int FINAL_COL = col;
int FINAL_ROW = row;
Button btn = new Button(this);
TableRow.LayoutParams linearLayoutParams2 = new TableRow.LayoutParams(TableRow.LayoutParams.MatchParent, TableRow.LayoutParams.MatchParent, 1.0f);
btn.LayoutParameters = linearLayoutParams2;
btn.Text = sqlReader["Name"].ToString();
tablerow.AddView(btn);
}
}
}
My result is below:
And my desired result is:
Where should I place my loop for getting the desired result? Or should I break it somehow?
Thanks.
Also what if I want to use two rows??
When confronted with a difficult problem, break it down into manageable bits (this is good coding practice anyway).
First, get the data you need into a single list. Don't forget to Dispose your DataReader.
public List<string> GetButtonNames()
{
var buttonNames = new List<string>();
SqlCommand sqlCmd = new SqlCommand("Select Name from TablesDesigner", con);
using (var sqlReader = sqlCmd.ExecuteReader())
{
while (sqlReader.Read())
{
buttonNames.Add(sqlReader["Name"].ToString());
}
}
return buttonNames;
}
Then write a function to organize it into a 2D list. I stole the logic for this from this question.
public static List<List<string>> Make2DList(List<string> input, int width=4)
{
var output = new List<List<string>>();
for (int i=0; i < input.Count; i+= width)
{
output.Add(input.GetRange(i, Math.Min(width, input.Count - i)));
}
return output;
}
Now you have a list of lists. The "outer" list corresponds to each table row. The inner list is a list of column values within that row.
Now all you need is code to make it into a table. Because we organized the data into a grid already, we can use normal foreach syntax which makes it very easy.
public void RenderButtonTable(List<List<string>> names)
{
var layout = new TableLayout.LayoutParams
(
TableLayout.LayoutParams.MatchParent,
TableLayout.LayoutParams.MatchParent,
1.0f
);
tablerow.LayoutParameters = layout;
foreach (var row in names)
{
TableRow tablerow = new TableRow(this);
tablerow.LayoutParameters = layout;
table.AddView(tablerow);
foreach (var col in row)
{
Button btn = new Button(this);
btn.Text = col;
tablerow.AddView(btn);
}
}
}
Put it all together:
void CreateDynamicButtonsWhileReadingFromSQLServer()
{
var buttonNames = GetButtonNames();
var gridData = Make2DList(buttonNames, NUM_COLS);
RenderButtonTable(gridData);
}

DataTable To Load A List

I've created a stored procedure (SP) and integrated that in the following way that works just fine:
Edited:
private DataTable GetSPResult()
{
int m = Convert.ToInt32(DropDownList1.SelectedValue);
int k = Convert.ToInt32(DropDownList2.SelectedValue);
DataTable ResultsTable = new DataTable();
var context = new DemoEntities();
var con = context.Database.Connection;
var connectionState = con.State;
try
{
using (context)
{
con.Open();
using (var cmd = con.CreateCommand())
{
cmd.CommandText = "MonthlyConsumption"; //Here is the SP
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#Para1", SqlDbType.Int));
cmd.Parameters["#Para1"].Value = m;
cmd.Parameters.Add(new SqlParameter("#Para2", SqlDbType.Int));
cmd.Parameters["#Para2"].Value = k;
using (var reader = cmd.ExecuteReader())
{
ResultsTable.Load(reader);
}
}
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (con != null)
{
con.Close();
}
}
return ResultsTable;
}
Finally done the below: On button click, I am able to see data in the report
protected void Button1_Click(object sender, EventArgs e)
{
DataTable dt = GetSPResult();
ReportViewer1.Visible = true;
ReportViewer1.LocalReport.ReportPath = Server.MapPath("Report1.rdlc");
ReportViewer1.LocalReport.DataSources.Clear();
ReportViewer1.LocalReport.DataSources.Add(new ReportDataSource("DataSet1", dt));
}
Output:
But when I try to convert a list to DataTable with ORM, it throws no exception but no data in the report as follows:
Output:
This is the code that I've done so far with ORM - Entity Framework that also works: By the way, I put breakpoint for debugging purpose and it gets the value but doesn't return data in the report
public DataTable GetSPResult()
{
int m = Convert.ToInt32(DropDownList1.SelectedValue);
int k = Convert.ToInt32(DropDownList2.SelectedValue);
DataTable ResultsTable = new DataTable();
var context = new DemoEntities();
using (context)
{
var query = context.MonthlyConsumption(m, k).ToList();
foreach (var item in query)
{
ResultsTable.Columns.Add("Store");
ResultsTable.Columns.Add("Product");
ResultsTable.Columns.Add("Jan");
ResultsTable.Columns.Add("Feb");
ResultsTable.Columns.Add("Mar");
ResultsTable.Columns.Add("Apr");
ResultsTable.Columns.Add("May");
ResultsTable.Columns.Add("Jun");
ResultsTable.Columns.Add("Jul");
ResultsTable.Columns.Add("Aug");
ResultsTable.Columns.Add("Sep");
ResultsTable.Columns.Add("Oct");
ResultsTable.Columns.Add("Nov");
ResultsTable.Columns.Add("Dec");
ResultsTable.Rows.Add(item.StoreName);
ResultsTable.Rows.Add(item.ItemName);
ResultsTable.Rows.Add(item.M1.Value);
ResultsTable.Rows.Add(item.M2.Value);
ResultsTable.Rows.Add(item.M3.Value);
ResultsTable.Rows.Add(item.M4.Value);
ResultsTable.Rows.Add(item.M5.Value);
ResultsTable.Rows.Add(item.M6.Value);
ResultsTable.Rows.Add(item.M7.Value);
ResultsTable.Rows.Add(item.M8.Value);
ResultsTable.Rows.Add(item.M9.Value);
ResultsTable.Rows.Add(item.M10.Value);
ResultsTable.Rows.Add(item.M11.Value);
ResultsTable.Rows.Add(item.M12.Value);
}
}
return ResultsTable;
}
Note and Updated: Could I convert the List to a IDataReader to load it or is there any simple way to make it done? I've seen some of the tutorials where the author has used foreach loop to iterate the list and then bind it to the DataTable. But I am just trying to simply load the list to the DataTable.
Finally got it done. Just converted the list to DataTable using the following method:
public DataTable ToDataTable<T>(List<T> items)
{
DataTable ResultsTable = new DataTable(typeof(T).Name);
//Gets all the properties
PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo prop in Props)
{
//Sets column names as Property names
ResultsTable.Columns.Add(prop.Name);
}
foreach (T item in items)
{
var values = new object[Props.Length];
for (int i = 0; i < Props.Length; i++)
{
//Inserts property values to datatable rows
values[i] = Props[i].GetValue(item, null);
}
ResultsTable.Rows.Add(values);
}
return ResultsTable;
}

Why do i get System.Data.DataRow?

I wanna show my rows in a listbox and the table names but when i run my code it says System.Data.DataRow can someone help me
my code is
foreach (object SelectedValue in ListEmployees.SelectedItems)
{
using (connection = new SqlConnection(connectionstring))
using (SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM " + selectedCel, connection))
{
DataTable employees = new DataTable();
adapter.Fill(employees);
for (int i = 0; i < employees.Rows.Count; i++)
{
DataRow dr = employees.Rows[i];
ListViewItem itm = ListViewItem(dr.ToString());
listView1.Items.Add(itm);
}
}
}
DataRow.ToString() just prints out the full type name.
Presuming you want to show the first column:
ListViewItem itm = new ListViewItem(dr.Field<string>(0));
i wanna show all columns that are in the table
string[] allColumns = dr.ItemArray.Select(obj => obj.ToString()).ToArray();
ListViewItem itm = new ListViewItem(allColumns);

Categories

Resources