How to return names of all columns? - c#

Searching, I found the PRAGMA as a possible solution for my problem, but it only returns the index of each column. There's any other method to return all columns names?
I thought using a For to go through my column indexes returning their names would works fine, but I dont exactly know how the syntax of this would be, either the stop condition.
void FillColumnList()
{
try
{
string check = "SELECT * FROM PRAGMA table_info(Produtos)";
sqlCon.Open();
SQLiteCommand tst2 = new SQLiteCommand(check, sqlCon);
SQLiteDataReader rdr2 = tst2.ExecuteReader();
if (rdr2.HasRows)
{
while (rdr2.Read())
{
string columns = rdr2[0].ToString();
Columns.Add(columns);
}
sqlCon.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
This code should return and fill the Global variable list Columns with the name of each column of "Produtos" table. Instead of it, my DataReader 'rdr2' return false in the HasRows, even when there's columns and Datas in my table "Produtos"

You can use the connection's GetSchema method to retrieve the column information. I'm using the following code to insert information my own class TableColumn not shown here:
string[] restrictions = new string[] { null, null, tableName };
using (DataTable columns = conn.GetSchema("Columns", restrictions)) {
int nameIndex = columns.Columns.IndexOf("COLUMN_NAME");
int ordinalPosIndex = columns.Columns.IndexOf("ORDINAL_POSITION");
int isNullableIndex = columns.Columns.IndexOf("IS_NULLABLE");
int maxLengthIndex = columns.Columns.IndexOf("CHARACTER_MAXIMUM_LENGTH");
int dataTypeIndex = columns.Columns.IndexOf("DATA_TYPE");
int isPrimaryKeyIndex = columns.Columns.IndexOf("PRIMARY_KEY");
int hasDefaultIndex = columns.Columns.IndexOf("COLUMN_HASDEFAULT");
int defaultValueIndex = columns.Columns.IndexOf("COLUMN_DEFAULT");
foreach (DataRow row in columns.Rows) {
var col = new TableColumn {
ColumnName = (string)row[nameIndex]
};
try {
col.ColumnNameForMapping = prepareColumnNameForMapping(col.ColumnName);
} catch (Exception ex) {
throw new UnimatrixExecutionException("Error in delegate 'prepareColumnNameForMapping'", ex);
}
col.ColumnOrdinalPosition = (int)row[ordinalPosIndex];
col.ColumnAllowsDBNull = (bool)row[isNullableIndex];
col.ColumnMaxLength = (int)row[maxLengthIndex];
string explicitDataType = ((string)row[dataTypeIndex]).ToLowerInvariant();
col.ColumnDbType = GetColumnDbType(explicitDataType);
col.ColumnIsPrimaryKey = (bool)row[isPrimaryKeyIndex];
col.ColumnIsIdentity = explicitDataType == "integer" && col.ColumnIsPrimaryKey;
col.ColumnIsReadOnly = col.ColumnIsIdentity;
if ((bool)row[hasDefaultIndex]) {
col.ColumnDefaultValue = GetDefaultValue(col.ColumnDbType, (string)row[defaultValueIndex]);
if (col.ColumnDefaultValue == null) { // Default value could not be determined. Probably expression.
col.AutoAction = ColumnAction.RetrieveAfterInsert;
}
}
tableSchema.ColumnSchema.Add(col);
}
}
You can simplify this code considerably if you only need the column names.

Related

How do I return multiple rows of parameter data with C#

I'm using C# to extract data to T-SQL parameters, the query is:
DECLARE #Param1 INT, #Param2 NCHAR(50), #P3 REAL, #P4 BIT
SELECT #Param1 = [idx]
,#Param2 = [data]
,#P3 = [itgetsreal]
,#P4 = [wazzup]
FROM [T].[dbo].[temp];
Running from MS SQL Server Management Studio yields a predictable one line dataset, the last. My C# code creates output parameters:
public class ParamData
{ // query has executed, return parameter data in class properties
public string[] names; public Object[] vals; public bool success = false;
public ParamData(SqlCommand cmd)
{
if (cmd == null) {
err = "SqlCommand \"cmd\" may not be NULL";
errcode = -1; errdata = ""; errsrc = "ParamData(SqlCommand cmd)"; }
else {
if (cmd.Parameters == null) { err = "\"SqlCommand.Parameters\" may not be NULL";
errcode = -1; errdata = cmd.CommandText; errsrc = "ParamData(SqlCommand cmd)"; }
else {
try {err = ""; errcode = 0; errdata = ""; errsrc = "";
int cnt = cmd.Parameters.Count;
if (cnt > 0) {
names = new string[cnt]; vals = new object[cnt];
for (int i = 0; i < cnt; i++)
{
names[i] = cmd.Parameters[i].ParameterName;
vals[i] = cmd.Parameters[i].Value;
}
}
success = true;
}
catch (SqlException ex) {
err = ex.Message; errcode = ex.Number;
errdata = String.Format("Parameters name/val assignment: Query: \"{0}\"",
cmd.CommandText);
errsrc = "ParamData(SqlCommand cmd)";}
}
}
}
}
How do I create a SqlReader type object where I can extract each row of the dataset and not only the last?
BTW: I've got means already to bring in the data without parameters but am constrained to provide a legacy compatibility and can't yet replicate the original function.
You can't return multiple rows of T-SQL variables/parameters. Parameters only hold the last value.
The comments are spot on - one needs to return datasets (not through parameters) to obtain multiple rows.

Testing DB content, Zooming in on 1 value

I have a SQLite database that returns 1 number to
Select value from Income where symbol = "AE" and statementitem = "Revenues" and periodtype = "Annual" and yearmonth = "Dec 2019"; --1811.2
I use a bit of c# code to test this to make sure nothing is missed:
public string GetIncome(string dbFile, string symbol, string aq, string yearmonth)
{
var answer = String.Empty;
try
{
using (var con = new SQLiteConnection($"URI=file:{dbFile}"))
{
con.Open();
using var cmd = new SQLiteCommand(con)
{
CommandText = $"Select value from Income where symbol = '{symbol}' and statementitem = 'Revenues' and periodtype = '{aq}' and yearmonth = '{yearmonth}';"
};
using SQLiteDataReader dataReader = cmd.ExecuteReader();
while (dataReader.Read())
{
answer = dataReader.GetString(1);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw ex;
}
return answer;
}
This errors out with System.IndexOutOfRangeException : Index was outside the bounds of the array.
Whats the best way to pick up on that value please?
See official docs:
https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlite.sqlitedatareader.getstring?view=msdata-sqlite-3.1.0#Microsoft_Data_Sqlite_SqliteDataReader_GetString_System_Int32_
It tells that GetString only argument is "The zero-based column ordinal". In your case you're trying to access second item (by index 1), but your query has only single field returned. Use index 0 in
answer = dataReader.GetString(0);

insert only new data instead duplicate the existing data

I have this code running calling the data from the core system,
public int MuatTurunMTS(hopesWcfRef.Manifest2 entParam, string destination, int capacity)
{
try
{
EL.iSeriesWcf.IiSeriesClient iClient = new iSeriesWcf.IiSeriesClient();
EL.iSeriesWcf.Manifest2 manifest2 = new iSeriesWcf.Manifest2();
manifest2 = iClient.GetManifest2(entParam.NOKT, destination, capacity);
DataTable dt = new DataTable();
dt = manifest2.Manifest2Table;
List<hopesWcfRef.Manifest2> LstManifest2 = new List<hopesWcfRef.Manifest2>();
for (int i = 0; i < dt.Rows.Count; i++)
{
hopesWcfRef.Manifest2 newDataRow = new hopesWcfRef.Manifest2();
newDataRow.NOPASPOT = dt.Rows[i][1].ToString();
newDataRow.NOKT = dt.Rows[i][0].ToString();
newDataRow.KOD_PGKT = dt.Rows[i][2].ToString();
newDataRow.KOD_KLGA = dt.Rows[i][3].ToString();
newDataRow.NAMA = dt.Rows[i][4].ToString();
newDataRow.TKHLAHIR = (dt.Rows[i][5].ToString() == "1/1/0001 12:00:00 AM" ? DateTime.Now : Convert.ToDateTime(dt.Rows[i][5])); //Convert.ToDateTime(dt.Rows[i][5]);
newDataRow.JANTINA = dt.Rows[i][6].ToString();
newDataRow.WARGANEGARA = dt.Rows[i][7].ToString();
newDataRow.JNS_JEMAAH = dt.Rows[i][8].ToString();
newDataRow.NO_SIRI = dt.Rows[i][9].ToString();
newDataRow.NO_MS = Convert.ToInt16(dt.Rows[i][10]);
newDataRow.BARKOD = dt.Rows[i][13].ToString();
newDataRow.NO_DAFTAR = dt.Rows[i][14].ToString();
//bydefault make cell empty
newDataRow.STS_JEMAAH = "";
newDataRow.SEAT_NO = "";
newDataRow.SEAT_ZONE = "";
newDataRow.BERAT = 0;
newDataRow.JUM_BEG = 0;
LstManifest2.Add(newDataRow);
}
int cntr = 0;
if (LstManifest2.Count != 0)
{
foreach (hopesWcfRef.Manifest2 manifest in LstManifest2)
{
cntr++;
SaveManifestTS(manifest);
}
}
return LstManifest2.Count;
}
catch (Exception ex)
{
throw ex;
}
}
And goes to :
public void SaveManifestTS(hopesWcfRef.Manifest2 manifest)
{
try
{
ent.BeginSaveChanges(SaveChangesOptions.Batch, null, null);
ent.AddObject("Manifest2", manifest);
ent.SaveChanges(SaveChangesOptions.Batch);
}
catch (Exception ex)
{
//Uri u = new Uri(ent.BaseUri + "GetErrorMsg"
// , UriKind.RelativeOrAbsolute);
//string datas = (ent.Execute<string>(u)).FirstOrDefault();
//Exception ex = new Exception(datas);
throw ex;
}
}
When SaveChanges run, if the data exist it will duplicate the entire row,
How to avoid the data being duplicate when insert (savechanges)??????
Many Thanks
What about: Do not insert.
In these cases I am using a MERGE statement that updates existing data (based on primary key) and inserts new data.
Oh, and all the code example you loved to post is totally irrelevant to the question, which is a pure SQL side question. You literally quote your car manual then asking which direction to turn.

Data is not saving into database in a right manner

private void SaveButton_Click(object sender, EventArgs e)
{
try
{
if (CashPaymentGridView.Rows.Count > 1)
{
CashPaymentandReceivedE cashpament =new CashPaymentandReceivedE();
List<CashPaymentandReceivedE> cashpaymentList = new List<CashPaymentandReceivedE>();
foreach ( DataGridViewRow rows in CashPaymentGridView.Rows)
{
if (rows.IsNewRow )
{
break ;
}
cashpament.VR_NO= Convert.ToInt16(VoucherNoTextBox.Text);
cashpament.VR_DATE = VrDate.Value ;
cashpament.ETYPE = "CPV";
cashpament.USER_ID = "1";
cashpament.PARTY_ID= Convert.ToString (rows.Cells[2].Value) ;
cashpament.DESCRIPTION = Convert.ToString ( rows.Cells[3].Value);
cashpament.INVOICE = Convert.ToString(rows.Cells[4].Value);
cashpament.DEBIT = Convert.ToInt32(rows.Cells[5].Value);
cashpament.CREDIT = 0;
cashpaymentList.Add(cashpament);
cashpament = new CashPaymentandReceivedE();
cashpament.VR_NO =Convert.ToInt16(VoucherNoTextBox.Text);
cashpament.VR_DATE = VrDate.Value;
cashpament.ETYPE = "CPV";
cashpament.USER_ID = "1";
cashpament.PARTY_ID = NewAccountsDAL.Get_Id_Name ("CASH");
cashpament.DESCRIPTION = Convert.ToString(rows.Cells[3].Value);
cashpament.INVOICE = Convert.ToString(rows.Cells[4].Value);
cashpament.CREDIT = Convert.ToInt32(rows.Cells[5].Value);
cashpament.DEBIT = 0;
cashpaymentList.Add(cashpament);
}
if (CashPaymentandReceivedDAL.Save(cashpaymentList))
{
MessageBox.Show("SAVE SUCCESSFULLY...............");
ResetForm();
}
}
else
{
MessageBox.Show ("Please select atleast one record.....");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message );
}
}
Stored Procedure for saving data is given as.
public static bool Save(List <CashPaymentandReceivedE> cashreceivedpayment)
{
bool blnResult = false;
SqlConnection objSqlConnection = new SqlConnection(ConnectionString.Connection);
//SqlTransaction objSqlTransaction = null;
try
{
objSqlConnection.Open();
//objSqlTransaction = objSqlConnection.BeginTransaction();
int R = 0;
while (R < cashreceivedpayment.Count )
{
SqlCommand objSqlCommand = new SqlCommand("CASHRECEIVED_Save", objSqlConnection);
objSqlCommand.CommandType = CommandType.StoredProcedure;
//SqlParameter objIdentityParameter = objSqlCommand.Parameters.Add("#PLED_ID", SqlDbType.BigInt);
//objIdentityParameter.Direction = ParameterDirection.Output;
//objSqlCommand.Parameters.AddWithValue("#PLED_ID", cashreceivedpayment[R].PLED_ID);
objSqlCommand.Parameters.AddWithValue("#COMPANY_ID", "1");
objSqlCommand.Parameters.AddWithValue("#PARTY_ID", cashreceivedpayment[R].PARTY_ID);
objSqlCommand.Parameters.AddWithValue("#VR_NO", cashreceivedpayment[R].VR_NO);
objSqlCommand.Parameters.AddWithValue("#ETYPE", cashreceivedpayment[R].ETYPE);
objSqlCommand.Parameters.AddWithValue("#VR_DATE", cashreceivedpayment[R].VR_DATE);
objSqlCommand.Parameters.AddWithValue("#DESCRIPTION", cashreceivedpayment[R].DESCRIPTION);
objSqlCommand.Parameters.AddWithValue("#DEBIT", cashreceivedpayment[R].DEBIT);
objSqlCommand.Parameters.AddWithValue("#CREDIT", cashreceivedpayment[R].CREDIT);
objSqlCommand.Parameters.AddWithValue("#USER_ID", cashreceivedpayment[R].USER_ID);
//objSqlCommand.Parameters.AddWithValue("#COMPNAY_ID", cashreceivedpayment[R].COMPANY_ID);
objSqlCommand.Parameters.AddWithValue("#DESCRIPTION2", "DESCRIPTION2");
objSqlCommand.Parameters.AddWithValue("#INVOICE", cashreceivedpayment[R].INVOICE);
objSqlCommand.ExecuteNonQuery();
R++;
blnResult = true;
}
}
catch (Exception ex)
{
//objSqlTransaction.Rollback();
MessageBox.Show(ex.Message);
}
finally
{
//objSqlTransaction.Commit();
objSqlConnection.Close();
}
return blnResult;
}
When i save the record, one record should be of Party_id and one should be of cash.
but when i select more than one record just one entry saving to cash. when when i load the record jst one record is loaded.plz help if u understand.....
You're creating one CashPaymentandReceivedE object, and adding the reference to it on each iteration of the list. You're then also changing all the data within that single object on each iteration. Just move this line:
CashPaymentandReceivedE cashpament =new CashPaymentandReceivedE();
... inside your foreach statement and the problem should be resolved.
Before you do so though, make sure you understand why your code is behaving like this. It's really important to understand that the list doesn't contain objects - it contains references to objects. In your case, it would contain several references to a single object, until you fix it.
I'd also strongly suggest using a foreach in your Save method - or if you really need the index for some reason, use a for loop instead of a while.

How do I check if specified column exists in MS Access database?

I need my program check if specified column exists in MS Access 2000 database, and if it doesn't - add it. I use .NET Framework 2.0
I tried to use oleDbConnection.GetSchema() method, but couldn't find column names in metadata (i'm really not a pro, huh) and any specification on msdn.
I would appreciate any help.
Thanks for answers.
Here is solution i used in my code:
bool flag = false; string[] restrictions = new string[] { null, null, mytable };
DataTable dtColumns = oleDbConnection1.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Columns, restrictions);
foreach (DataRow row in dtColumns.Rows)
{
if (mycolumnname==(string)row["COLUMN_NAME"]) flag = true;
}
This is code that is part of a o/r-mapper of mine. You cannot use it as is beacuse it depends on other classes, but I hope you get the picture.
Define restrictions like this
string[] restrictions = new string[] { null, null, tableName };
This retrieves the columns from a table
private void RetrieveColumnInfo(OleDbConnection cnn, TableSchema tableSchema,
string[] restrictions, Func<string, string> prepareColumnNameForMapping)
{
using (DataTable dtColumns =
cnn.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, restrictions)) {
string AutoNumberColumn = RetrieveAutoNumberColumn(cnn, tableSchema);
foreach (DataRow row in dtColumns.Rows) {
var col = new TableColumn();
col.ColumnName = (string)row["COLUMN_NAME"];
try {
col.ColumnNameForMapping =
prepareColumnNameForMapping(col.ColumnName);
} catch (Exception ex) {
throw new UnimatrixExecutionException(
"Error in delegate 'prepareColumnNameForMapping'", ex);
}
col.ColumnAllowsDBNull = (bool)row["IS_NULLABLE"];
col.ColumnIsIdentity = col.ColumnName == AutoNumberColumn;
DbColumnFlags flags = (DbColumnFlags)(long)row["COLUMN_FLAGS"];
col.ColumnIsReadOnly =
col.ColumnIsIdentity ||
(flags & (DbColumnFlags.Write | DbColumnFlags.WriteUnknown)) ==
DbColumnFlags.None;
if (row["CHARACTER_MAXIMUM_LENGTH"] != DBNull.Value) {
col.ColumnMaxLength = (int)(long)row["CHARACTER_MAXIMUM_LENGTH"];
}
col.ColumnDbType = GetColumnDbType((int)row["DATA_TYPE"]);
col.ColumnOrdinalPosition = (int)(long)row["ORDINAL_POSITION"];
GetColumnDefaultValue(row, col);
tableSchema.ColumnSchema.Add(col);
}
}
}

Categories