Table schema as DataTable? - c#

I did a search and found some seemingly related answers, but they don't really do what I'm after.
Given a valid connection string and a table name, I want to get a DataTable of the table. I.e. if the table has a column called "Name", I want the DataTable set up so I can do dt["Name"] = "blah";
The trick is, I don't want to hard code any of that stuff, I want to do it dynamically.
People tell you to use SqlConnection.GetSchema, but that gives you back a table with a bunch of stuff in it.
Everybody has random tricks like TOP 0 * from the table and get the schema from there, etc.
But is there a way to get the table with the primary keys, unique indexes, etc. Ie.. in the final format to do a bulk insert.

You can use SqlDataAdapter.FillSchema:
var connection = #"Your connection string";
var command = "SELECT * FROM Table1";
var dataAdapter = new System.Data.SqlClient.SqlDataAdapter(command, connection);
var dataTable = new DataTable();
dataAdapter.FillSchema(dataTable, SchemaType.Mapped);
This way you will have an empty DataTable with columns and keys defined and ready to use in code like dataTable["Name"] = "blah";.

Related

Displaying last record after insertion c#

I read upon a document on how to retrieve the last record after inserted. However when I do, nothing gets filled on the datagridview. This is what I have.
static String connectionString = #"Data Source = (LocalDB)\MSSQLLocalDB;AttachDbFilename= C:\Users\home\Documents\C# Programs\program\Database.mdf ;Integrated Security = True";
private void displayLastInsertedRecord()
{
using (SqlDataAdapter dataAdapter = new SqlDataAdapter("select ##identity", connectionString))
{
DataTable table = new DataTable(connectionString);
dataAdapter.Fill(table);
employeeDataGridView.DataSource = table;
}
}
I checked to see if in fact the data is being stored into the database table and it actually is. It just not display factors such as their name, city, address, etc etc.Cannot figure out what I am doing incorrectly.
Your query is returning a single row, single column table, which contains the Primary Key value of the last inserted data row, in any table in your database, provided that such primary key is an IDENTITY column. Since you want the actual data, change your query from:
SELECT ##IDENTITY
to:
SELECT #LastID = ##IDENTITY; SELECT * FROM [YourTableName] WHERE [YourPrimaryKeyColumn] = #LastID
where [YourTableName] is the table you're interested in getting the inserted row from (must match last insert command, otherwise the returned dataset will either contain no rows, or have an accidentally matching record - basically, garbage data), and [YourPrimaryKeyColumn] is the name of the primary key column in the aforementioned table.
Also, consider using SCOPE_IDENTITY or IDENT_CURRENT instead.

Create column from another table dynamically

I'm working with TSQL and C#. I have two queries that return strings:
string[] allSubcategories = dt.AsEnumerable().Select(x => x.Field<string>("SubcategoryName")).Distinct().ToArray();
var redMark = db.GetTableBySQL("SELECT * FROM RedMarkItems");
string[] redMarkColumns = redMark.Columns.Cast<DataColumn>().Select(x => x.ColumnName).ToArray();
So, as you can see I have two different arrays, first I get subcategoriesNames:
and all columns of table RedMarkItems:
That I want to do is to create column dynamically, I mean, if subcategorieName does not exist as column in RedMarkItems do an Update and create it someting like:
var createColumn = db.ExeSQL($"ALTER TABLE RedMarkItems ADD {ColumnName} BIT");
How can I compare if subcategorieName does not exist as column in RedMarkItems table? Then create column as my query? Regards
If you want to know if a particular column exists in an already filled DataTable using the Linq approach then it is just:
bool exists = redMark.Columns.Cast<DataColumn>().Any(x => x.ColumnName == "SubCategoryName");
Instead, if you want to ask this info directly to the database then use the INFORMATION_SCHEMA views The Columns view is the one to use with a query like this.
string query = #"IF EXISTS(SELECT 1 FROM INFORMATION_SCHEMA.Column
WHERE Column_Name = #colName)
SELECT 1 ELSE SELECT 0";
SqlCommand cmd = new SqlCommand(query, connection);
cmd.Parameters.Add("#colName", SqlDbType.NVarChar).Value = "SubCategoryName";
bool exists = (cmd.ExecuteScalar() == 1);
Now, the part about creating the column is pretty simple as code per se. It is just an appropriate ALTER TABLE. But there are a lot of things to be cleared before. What will be the datatype of the new column? What will be its length and precision? What will be the constraints applied to it (Null/Not Null defaults etc)? As you can see all these info are very important and require to be defined somewhere in your code.

How to change values of column of DataTable and show only in DataGrid not updating actual table of database

I have a column with encrypted name(all other columns are not encrypted) in SQL Database table. And I have to decrypt the column with encrypted name to show in DataGrid to users of my application but the actual table of SQL database should not be changed.(has to remain as encrypted name).
I think UpdateCommand works to update the actual table and I have to find an alternative than below UpdateCommand.
Or is there alternative way to decrypt only 1 column on DataTable which is not influencing the actual table of database?
My simple code is,
SqlCommand gridcomm = new SqlCommand();
gridcomm.Connection = Conn;
gridcomm.CommandText = "SELECT Id, customername, phonenumber FROM customers";
SqlDataAdapter gridda = new SqlDataAdapter(gridcomm);
SqlDataReader gridreader = gridcomm.ExecuteReader();
while (gridreader.Read())
{
}
gridreader.Close();
DataTable griddt = new DataTable("customers");
gridda.Fill(griddt);
foreach (DataRow row in griddt.Rows)
{
string strcustomername = (string) row["customername"].ToString();
bytecustomername = Convert.FromBase64String(strcustomername);
string decryptedcustomername = DecryptStringFromBytes_Aes(bytecustomername, byteAESKey, byteAESIV);
row["customername"] = decryptedcustomername;
}
gridda.UpdateCommand = new SqlCommandBuilder(gridda).GetUpdateCommand();
dataGrid_Totalcustomerlist.ItemsSource = griddt.DefaultView;
gridda.Update(griddt);
Hello Kay Lee: I think that if you look at implementing a Coverter in your View you will get exactly what you are looking for. In your IValueConverter implementation you can Implement the Decrypt routine. A Converter is the extended syntax in a WPF Binding Statement. If this is not clear then I will flesh out some more. Here is a great reference for Converters: http://www.wpf-tutorial.com/data-binding/value-conversion-with-ivalueconverter/
Kind Regards,
Mark Wardell
I've read many posts but there were no solution for me as this case is unusual. However, I just thought logically and finally found solution by myself.
We just need to delete 2 line of Update related code because we don't need to update.
gridda.UpdateCommand = new SqlCommandBuilder(gridda).GetUpdateCommand();
gridda.Update(griddt);
Hope this helps someone..

OleDB Data not reading from the correct row

I have the following method created and previously stock1Label to stock3Label were able to output the correct values from the database however after i added more rows to my ProductsTable, source.Rows[0][0], [1][0], etc. seems to be taking values from row 8 onwards of my table instead of row 1, anyone know why this is happening?
private void UpdateStocks()
{
string query = "SELECT pQty FROM ProductsTable";
OleDbDataAdapter dAdapter = new OleDbDataAdapter(query, DBconn);
DataTable source = new DataTable();
dAdapter.Fill(source);
stock1Label.Text = source.Rows[0][0].ToString();
stock2Label.Text = source.Rows[1][0].ToString();
stock3Label.Text = source.Rows[2][0].ToString();
stock4Label.Text = source.Rows[3][0].ToString();
stock5Label.Text = source.Rows[4][0].ToString();
stock6Label.Text = source.Rows[5][0].ToString();
}
Most (all?) database systems do not have defined orders.
You will receive rows in non-determinstic storage order, not in the order you inserted them.
To receive a meaningful consistent ordering, you need to add an ORDER BY clause.

Why do I get empty results using generated code from DB?

I'm using SQL Server 2005. I have a table scores with 6 rows and columns - name, score and id.
I added the data source with VS and it generated a dataset called testDataSet.
So I tried the following code which gives me zero results:
testDataSet db = new testDataSet();
var result = from row in db.scores
select row.name;
Where is the problem?
The probem you are having is that you are querying an empty DataSet.
You first have to create a connection to your testDataSet and fill the tables contained in it with data from your database.
If you have created testDataSet with the automated tools VS provides then the tool will have also created the relevant TableDataAdapters (in their own namespace) to fill and update your DataSet.
Initialize the relevant TableDataAdapter and fetch the data from the database with the Fill(db) method.
you sould query dataTable like this:
DataTable products = ds.Tables["Product"];
var query = products.AsEnumerable().
Select(product => new
{
ProductName = product.Field<string>("Name"),
ProductNumber = product.Field<string>("ProductNumber"),
Price = product.Field<decimal>("ListPrice")
});
Try this code instead:
scoresTableAdapter adapter = new scoresTableAdapter();
var result = from row in adapter.GetData() select row.name;
Others are right that your problem is that you are not querying the data. When you generated the dataset, an adapter is also generated for you, that will help you to query the data as shown above.
The DataSet is just a structured container for the query results, it has no connection to the data source (database). In order to populate the DataSet with data you need to use a DataAdapter with a SelectCommand and call the Fill method.
var myConn = new SqlConnection ("..." );
var myAdapter = new SqlDataAdapter ( "SELECT * FROM TableName", myConn );
var myData = new testDataSet( );
myAdapter.Fill ( myData, "TableName" );

Categories

Resources