Get Columns of a Table by GetSchema() method - c#

I want to get list of columns of a table using GetSchema method in ADO.Net, my code is:
var dtCols = con.GetSchema("Columns", new[] { "DBName", "TableName" });
And i get an empty DataTable, what is the problem?

You must specify a parameter for the "owner" restriction.
var dtCols = con.GetSchema("Columns", new[] { "DBName", null, "TableName" });

This is my complete solution.
You just need to provide tableName and connectionString to this method:
// I took HUGE help from this Microsoft website: - AshishK
// https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlconnection.getschema?view=netframework-4.7.2#System_Data_SqlClient_SqlConnection_GetSchema_System_String_System_String___
public static List<string> GetAllColumnNamesOfATable(string tableName, string connectionString)
{
var allColumnNames = new List<string>();
using (var connection = new SqlConnection(connectionString))
{
// Connect to the database then retrieve the schema information.
connection.Open();
// You can specify the Catalog, Schema, Table Name, Column Name to get the specified column(s).
// You can use four restrictions for Column, so you should create a 4 members array.
String[] columnRestrictions = new String[4];
// For the array, 0-member represents Catalog; 1-member represents Schema;
// 2-member represents Table Name; 3-member represents Column Name.
// Now we specify the Table_Name and Column_Name of the columns what we want to get schema information.
columnRestrictions[2] = tableName;
DataTable allColumnsSchemaTable = connection.GetSchema("Columns", columnRestrictions);
foreach (DataRow row in allColumnsSchemaTable.Rows)
{
var columnName = row.Field<string>("COLUMN_NAME");
//You can capture other fields as well, like so:
//var dataType = row.Field<string>("DATA_TYPE");
//var characterMaxLength = row.Field<int?>("CHARACTER_MAXIMUM_LENGTH");
allColumnNames.Add(columnName);
}
connection.Close();
}
return allColumnNames;
}
PS: If you'd like to capture other information about the columns this way, the following fields are also available:

Could both of these answers be generalized a bit with:
dtCols = con.GetSchema("Columns", new[] {con.DataSource, null, "TableName"});
This is assuming that "TableName" is the name of the table that you want the schema for.

I had a similar problem, the following worked..
using(SqlCommand command = new SqlCommand(sqlText, con)) {
var sqlReader = command.ExecuteReader();
var a = sqlReader.GetColumnSchema();
}

Related

UWP Custom Sqlite Query to JSON

I'm searching for a way to Execute Custom SQL Queries and to provide the result in JSON. Normally you have to provide a Class for the Query result e.g.
var query = dbConn.Query<ClassTypes>("Select a as key, b as value FROM table WHERE id = ?", new object[] { ObjectID });
But in my case, I don't know the SQL Statement, because its provided by an external JavaScript from a Webview.
This Webview might ask my application to Execute
Select a.col1 as foo,b.col1, a.col2 FROM table1 a INNER JOIN table2 b ON a.id=b.aid
And wants me to return:
foo:xxx
col2:yyy
Which columns are "asked" by the SQL Statement is completely free, or which aliases are used, I just want to execute the Statement an return key value pairs with the aliases or column names and the values in a JSON (for each row).
So I'm not able to prepare a custom Class for the Query, because I don't know the format of the SQL Query.
Does anyone have an idea?
I just want to execute the Statement an return key value pairs with the aliases or column names and the values in a JSON (for each row).
For your scenario, You could use SqlDataReader to approach, SqlDataReader contains GetName method that could use to get the column name as key, and it also contains GetSqlValue method that could retrieve column's value. If you can't confirm the field count, you could also use FieldCount to get current reader 's field counts
For example
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
if (conn.State == System.Data.ConnectionState.Open)
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = GetProductsQuery;
using (SqlDataReader reader = cmd.ExecuteReader())
{
var list = new List<Dictionary<string, object>>();
while (reader.Read())
{
var dict = new Dictionary<string, object>();
var i = 0;
do
{
var key = reader.GetName(i);
var value = reader.GetSqlValue(i);
dict.Add(key, value);
i++;
} while (i < reader.FieldCount);
list.Add(dict);
}
}
}
}
}
For more detail please refer this document.

Get many rows from a list of IDs

I'm using C# and SQL Server. I have a list of IDs for documents which corresponds to the primary key for a table in SQL Server that has a row for each document and the row contains (among other things) the ID and the document for that ID. I want to get the document in the row for each of the IDs. Currently, I execute a query for each ID, but since there are 10,000s of them, this runs a ton of queries and takes a very long time. It ends up being faster to simply load everything from the table into memory and then filter by the ids I have, but that seems inefficient and won't scale over time. If that doesn't make sense, hopefully the following code that takes a long time to run shows what I'm trying to do.
private static Dictionary<Guid, string> foo(IEnumerable<Guid> guids, SqlConnection conn)
{
using (SqlCommand command = new SqlCommand(null, conn))
{
command.CommandText = "select document from Documents where id = #id";
SqlParameter idParam = new SqlParameter("#id", SqlDbType.UniqueIdentifier);
command.Parameters.Add(idParam);
command.Prepare();
var documents = new Dictionary<Guid, string>();
foreach (var guid in guids)
{
idParam.Value = guid;
object obj = command.ExecuteScalar();
if (obj != null)
{
documents[guid] = (string)obj;
}
}
return documents;
}
}
I could programmatically construct query strings to use where clause like this: ".... where id in (ID1, ID2, ID3, ..., ID100)" to get 100 documents at a time or something like that, but this feels janky and it seems to me like there's got to be a better way.
I'm sure I'm not the only one to run into this. Is there an accepted way to go about this?
You can use Table-Valued Parameters with no limits in amount of guids
In the code you will create SqlParameter with all Id's you need to
First you need create type of parameter in the sql server
CREATE TYPE IdTableType AS TABLE
(
Id uniqueidentifier
);
Then in the code
private static Dictionary<Guid, string> foo(IEnumerable<Guid> guids, SqlConnection conn)
{
using (SqlCommand command = new SqlCommand(null, conn))
{
// use parameter as normal table in the query
command.CommandText =
"select document from Documents d inner join #AllIds a ON d.id = a.Id";
// DataTable is used for Table-Valued parameter as value
DataTable allIds = new DataTable();
allIds.Columns.Add("Id"); // Name of column need to be same as in created Type
foreach(var id in guids)
allids.Rows.Add(id);
SqlParameter idParam = new SqlParameter
{
ParameterName = "#AllIds",
SqlDbType=SqlDbType.Structured // Important for table-valued parameters
TypeName = "IdTableType", // Important! Name of the type must be provided
Value = allIds
};
command.Parameters.Add(idParam);
var documents = new Dictionary<Guid, string>();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
documents[guid] = reader[0].ToString();
}
}
return documents;
}
}
You don't need to prepare the command any more. Besides after first execution next queries will use same compiled query plan, because query text remain same.
You can bunch them into sets of ids and pass a table valued parameter into the query. With Dapper this looks a bit like:
connection.Query("select document from Documents where id in #ids", new { ids = guids});
BEWARE though theres an 8000 parameter limit in sql so you will need to batch up your reads.
btw.. I'd highly recommend looking at Dapper or another micro orm for this type of data access.

How to get DefaultValue of column from database schema in C#?

I'm trying to read information from my database schema in C# (.NET 4.5, SQL Server 2014). I was having trouble with some fields such as MaxLength/ColumnLength until I found a forum that mentioned setting the DataAdapter.MissingSchemaAction to MissingSchemaAction.AddWithKey. Unfortunately the DefaultValue field is still blank even for columns that have a default set in the "Default Value or Binding" in the Column Properties in SQL Server.
SqlDataAdapter dbadapter = new SqlDataAdapter(SELECT_STRING, CONN_STRING);
dbadapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;
DataTable tbl = new DataTable();
dbadapter.Fill(tbl);
// I actually looped through all rows/columns, but the net effect here is...
tbl.Columns[0].DefaultValue; // blank for all columns
// Also tried accessing the schema table available through DataReader
IDataReader reader = tbl.CreateDataReader();
DataTable schemaTbl = reader.GetSchemaTable();
/*
* There are different schema fields here than in DataColumn,
* but DefaultValue still blank. I looped through them all but...
*/
schemaTbl.Rows[0]["DefaultValue"]; // blank for all columns
How can I read the default value from a column in my table using .NET (preferably without resorting to querying SQL's sys.* tables).
Clarification
When creating or altering a table, you can set a default value of a column if none is provided. I'm trying to get the default value.
Example:
CREATE TABLE Person
(
Id int NOT NULL,
LastName varchar(255) NOT NULL,
FirstName varchar(255) NOT NULL,
HomeState varchar(2) DEFAULT 'NY'
)
Now if I say, INSERT INTO Person (Id, LastName, FirstName) VALUES (1, 'Doe', 'John') the HomeState will be 'NY' even though I didn't set it.
Try using the Microsoft.SqlServer.Smo library as below:
using (var connection = new SqlConnection("connectionString"))
{
var serverConnection = new ServerConnection(connection);
var server = new Server(serverConnection);
var database = server.Databases["databaseName"];
var table = database.Tables["tableName"];
foreach (Column column in table.Columns)
{
Console.WriteLine($"{column.Name} - default constraint: {column.DefaultConstraint?.Text ?? "None"}");
}
Console.ReadLine();
}
EDIT
Thanks to #Crowcoder who suggested the below simplification:
var serverConnection = new ServerConnection("serverName", "username", "password");
var server = new Server(serverConnection);
var database = server.Databases["databaseName"];
var table = database.Tables["tableName"];
foreach (Column column in table.Columns)
{
Console.WriteLine($"{column.Name} - default constraint: {column.DefaultConstraint?.Text ?? "None"}");
}
Console.ReadLine();

How to find the table i want in an sql server using entity framework

I am using a method which its purpose it to read from tables. The method has an input parameter, a string which will hold the name of the table I will pass and I want to read from. There are multiple tables. My code so far:
public List<dataTable> GetData(string name)
{
TableEntities db = new TableEntities();
db.Database.Connection.Open();
foreach (var readDb in db.SOMETHING_HERE) //here it should find the table which is equal to the table I'm passing as string name
{
dataTable data = new dataTable();
data.name = readDb.name;
There are many option at db. but I don't know which fits my needs.
It's not pretty, but you can try this:
using (TableEntities db = new TableEntities())
{
var type = Type.GetType("namespace." + tableName);
var query = db.Database.SqlQuery(type, "SELECT * FROM " + tableName);
foreach (var row in query)
{
PropertyInfo prop = type.GetProperty("NAME");
string name = (string)prop.GetValue(row);
}
}
I think you need to use reflection to achieve that: MSDN Reflection reference
You may want to try something along these lines: (assuming sample tables Employees and Departments)
public List<dataTable> GetData(string name)
{
using(TableEntities db = new TableEntities())
{
if(new Employees().GetType().ToString().Equals(name))
//Do query
}
}

Get table data from dynamically selected table in LINQ C#

I obtain a table reference as such:
public static void MyDataGrabbingClass<T>(MyModelCls Model) where T : class
{
DataContext dc = new DataContext(Config.ConnectionString);
//var ITable = (Devart.Data.Linq.ITable)dc.GetType().GetProperty(tableName).GetValue(dc, null);
//var table = dc.GetTable(ITable.GetType());
//var dataModel = dc.Mapping;
//Type tableType = ITable.GetType();
//var t = dc.Mapping.MappingSource.GetModel(typeof(DataContext)).GetMetaType(tableType);
var table = dc.GetTable<T>();
}
I want to then select the specific columns of data using:
var Query = from c in table where Model.DateToColName < Model.DateTo select (Model.ColSelections);
obviously I need to somehow map the table column, and not use Model.DateToColName in the where clause, how do I do this?
In other words, with my dynamically chosen table, how do i get the column data from a string column name
Unfortunately I don't think you'll be able to construct a dynamic query in LINQ (at least not easily). Take a look at Dapper.NET - it's a "simple object mapper for .NET" that might work for you, created by the makers of StackOverflow. For example, using Dapper.NET, your method might look like:
public static void MyDataGrabbingClass<T>(MyModelCls Model) where T : class
{
using (SqlConnection conn = new SqlConnecrion(Config.ConnectionString)
{
conn.Open();
string tableName = ...;
string dateToColumnName = ...;
// depending on how dateToColumnName is constructed, ensure it is not a SQL-injection risk
if (tableName.Any(c => !char.IsLetterOrDigit(c))
throw new ArgumentException("Invalid table name.");
if (dateToColumnName.Any(c => !char.IsLetterOrDigit(c))
throw new ArgumentException("Invalid column name.");
// Query is a
var results = conn.Query<T>("SELECT * FROM [" + tableName + "] WHERE [" + dateToColumnName + "] < #DateTo", new { DateTo = someDate });
...
}
}
Security concern: Dynamic SQL can be susceptible to SQL injection - so be sure that the dateToColumnName variable is not from user-input, or is sanitized or validated appropriately.

Categories