How to drop all tables from specific schema in C# SQL Server? - c#

I'm working on a database migration where I need to drop all the tables in a specific schema and then run another script to recreate them from another database.
I'm running into issues with trying to delete specific tables in the proper order.
Is there a SQL query that will order the tables in the correct order so they can be dropped properly?
Here is the code I am trying so far, but the tables are not in the proper order:
private void CreateDropStatementsAndRun(string schema)
{
string sql = string.Format(#"SELECT table_name
FROM information_schema.tables
WHERE table_schema = '{0}';", schema);
var connectionString = ConfigurationManager.ConnectionStrings["TARGET_DefaultConnection"];
StringBuilder sb = new StringBuilder();
var listOfTables = new List<string>();
using (SqlConnection conn = new SqlConnection(connectionString.ConnectionString))
{
conn.Open();
using (var command = new SqlCommand(sql, conn))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
listOfTables.Add(reader.GetString(0));
}
}
}
foreach (var item in listOfTables)
{
sb.AppendFormat("alter table {0}.{1} nocheck constraint all;", schema, item).AppendLine();
sb.AppendFormat("DROP TABLE IF EXISTS {0}.{1};", schema, item).AppendLine();
}
using (var cmd = new SqlCommand(sb.ToString(), conn))
{
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
}
}

Remember that there might be circular references between tables. There might be foreign key constraints from A -> B -> C -> A, for example.
Have a look at the approach in How to drop all tables in a SQL Server database? - but you will have to alter it to work with just your schema.

Here is my answer:
Focus on the ORDER BY dependency_level desc and then the where schema_Name = '{0}'
Here is where I found my answer: How to list tables in their dependency order (based on foreign keys)?
private void CreateDropStatementsAndRun(string schema)
{
string sql = string.Format(#"WITH cte (lvl, object_id, name, schema_Name) AS
(SELECT 1, object_id, sys.tables.name, sys.schemas.name as schema_Name
FROM sys.tables Inner Join sys.schemas on sys.tables.schema_id = sys.schemas.schema_id
WHERE type_desc = 'USER_TABLE'
AND is_ms_shipped = 0
UNION ALL SELECT cte.lvl + 1, t.object_id, t.name, S.name as schema_Name
FROM cte
JOIN sys.tables AS t ON EXISTS
(SELECT NULL FROM sys.foreign_keys AS fk
WHERE fk.parent_object_id = t.object_id
AND fk.referenced_object_id = cte.object_id )
JOIN sys.schemas as S on t.schema_id = S.schema_id
AND t.object_id <> cte.object_id
AND cte.lvl < 30
WHERE t.type_desc = 'USER_TABLE'
AND t.is_ms_shipped = 0 )
SELECT schema_Name, name, MAX (lvl) AS dependency_level
FROM cte
where schema_Name = '{0}'
GROUP BY schema_Name, name
ORDER BY dependency_level desc,schema_Name, name;", schema);
var connectionString = ConfigurationManager.ConnectionStrings["TARGET_DefaultConnection"];
StringBuilder sb = new StringBuilder();
var listOfTables = new List<string>();
using (SqlConnection conn = new SqlConnection(connectionString.ConnectionString))
{
conn.Open();
using (var command = new SqlCommand(sql, conn))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
listOfTables.Add(reader.GetString(1));
}
}
}
if (listOfTables.Count > 0)
{
foreach (var item in listOfTables)
{
sb.AppendFormat("DROP TABLE IF EXISTS {0}.{1};", schema, item).AppendLine();
}
using (var cmd = new SqlCommand(sb.ToString(), conn))
{
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
}
}
}

Related

MySql parameterized stored procedure does not work in C#

I have parameterized stored procedure (tested and works) in mysql.
I wanted to replace my long select statement with stored procedure in my code.
With select statement it worked but now I am not able to run it with sp (commented string req).
My stored procedure:
CREATE DEFINER=`root`#`%` PROCEDURE `GetProjectVM`(
IN projectName NVARCHAR(255)
)
BEGIN
select VirtualMachines.Name,
VirtualMachines.IpAddress,
VirtualMachines.DiskSize,
VirtualMachines.CPU,
VirtualMachines.Ram,
VirtualMachines.ImageUrl,
VirtualMachines.Role,
Hypervisors.Name as Hypervisor,
Managements.Netmask,
Managements.Gateway from VirtualMachines inner join Projects
on Projects.id = VirtualMachines.ProjectId inner join Hypervisors
on Hypervisors.HypervisorId = VirtualMachines.HypervisorId inner join Managements
on VirtualMachines.ManagementId = Managements.Id
where Projects.Name = projectName;
END
My code looks like:
private string _dbUrl;
private MySqlConnection _cnn;
public Dbmanagement(string dbUrl)
{
this._dbUrl = dbUrl;
this._cnn = new MySqlConnection(this._dbUrl);
}
private MySqlDataReader ExecuteMysqlCommand(string cmd)
{
_cnn.Open();
var result = new MySqlCommand(cmd, _cnn);
return result.ExecuteReader();
}
public IEnumerable<VM> GetProjectVM(string projectName)
{
var vmList = new List<VM>();
//string req =
// $"select VirtualMachines.Name,VirtualMachines.IpAddress,VirtualMachines.DiskSize,VirtualMachines.CPU,VirtualMachines.Ram,VirtualMachines.ImageUrl,VirtualMachines.Role,Hypervisors.Name as Hypervisor,Managements.Netmask,Managements.Gateway from VirtualMachines inner join Projects on Projects.id = VirtualMachines.ProjectId inner join Hypervisors on Hypervisors.HypervisorId = VirtualMachines.HypervisorId inner join Managements on VirtualMachines.ManagementId = Managements.Id where Projects.Name = \"{projectName}\" ;";
MySqlCommand cmd = new MySqlCommand("GetProjectVM", _cnn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#projectName", projectName);
var req = cmd;
var rd = ExecuteMysqlCommand(req.ToString());
while (rd.Read())
{
vmList.Add(new VM(rd));
}
_cnn.Close();
return vmList;
}
The problem - or at least the first problem - is how you're executing the command.
Calling ToString on a MySqlCommand is very unlikely to be able to convey all the relevant information. You're losing parameterization, command type etc.
Change this:
var req = cmd;
var rd = ExecuteMysqlCommand(req.ToString());
to
_cnn.Open();
var rd = req.ExecuteReader();
I'd also suggest not having a single MySqlConnection, but just constructing one when you need to, and letting the connection pool manage making that efficient. So something like:
using (var connection = new MySqlConnection(_dbUrl))
{
connection.Open();
using (var cmd = new MySqlCommand("GetProjectVM", connection))
{
cmd.CommandType = CommandType.StoredProcedure;
// Avoid AddWithValue where possible, to avoid conversion issues.
cmd.Parameters.Add("#projectName", MySqlDbType. VarChar).Value = projectName;
using (var reader = cmd.ExecuteReader())
{
var list = new List<VM>();
while (reader.Read())
{
list.Add(new VM(reader));
}
return list;
}
}
}

If Employee exists then return employee roles using ADO.net

The idea under REST is, if an http request may come for an unknown record, we return 404, if it exists then roles of the employee.
The naive way would be that I can do this in two SQL statements, check the result of the first return null if not found else proceed with retrieving roles. The caller can check if result of the function is null and can return 404 based on that otherwise it will dislay roles of the user.
"SELECT Id FROM Employee WHERE Id = #Id"
"SELECT * FROM Role WHERE EmployeeId = #Id"
My current implementation is:
public List<object> GetUserRolesById(int id)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
// statement 1
string sql = "SELECT Id FROM Employee WHERE Id = #Id";
using (SqlCommand command = new SqlCommand(sql, connection))
{
command.Parameters.Add("#Id", SqlDbType.Int, 32).Value = id;
using (SqlDataReader reader = command.ExecuteReader())
{
if (!reader.Read() || reader.IsDBNull(reader.GetOrdinal("Id")))
{
return null; // caller to return 404 if record not found
}
}
}
// statement 2
sql = #"SELECT Id, Name FROM Role WHERE EmployeeId = #Id";
using (SqlCommand command = new SqlCommand(sql, connection))
{
command.Parameters.Add("#Id", SqlDbType.Int, 32).Value = id;
using (SqlDataReader reader = command.ExecuteReader())
{
List<object> roles = new List<object>();
if (reader.Read())
{
for (int i = 0; i < roleIds.Length; i++)
{
roles.Add(new {Id = Int32.Parse(reader.GetString((0)), Name = reader.GetString(1)});
}
}
return roles;
}
}
}
}
Question:
How can I combine both SQL statements in one in a nicer way?
Edit
Following the answer, incorporating suggestions in my solution, minus the user non-existent condition.
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string sql = #"
SELECT Employee.Id, Role.Id AS [RoleId], Role.NAME AS [RoleName]
FROM Employee
LEFT OUTER JOIN EmployeeRole on Employee.Id = EmployeeRole.EmployeeId
LEFT OUTER JOIN Role on EmployeeRole.RoleId = Role.Id
WHERE Employee.Id = #Id";
using (SqlCommand command = new SqlCommand(sql, connection))
{
command.Parameters.Add("#Id", SqlDbType.Int).Value = id;
using (SqlDataReader reader = command.ExecuteReader())
{
List<object> roles = new List<object>();
while (reader.Read()) // 404 condition missing?
{
roles.Add(new {Id = reader.GetInt32(1), Name = reader.GetString(2)});
}
return roles;
}
}
}
Query 2
Will it work if we combine both queries? however, I don't know how to retrieve double query result from the reader.
string sql = #"SELECT FIRST FROM Employee WHERE Id = #Id;
SELECT Employee.Id, Employee.First, Role.Id AS [RoleId], Role.NAME AS [RoleName]
FROM Employee
LEFT OUTER JOIN EmployeeRole on Employee.Id = EmployeeRole.EmployeeId
LEFT OUTER JOIN Role on EmployeeRole.RoleId = Role.Id
WHERE Employee.Id = #Id2";
I'd suggest using SQL like:
SELECT Employee.Id, Role.WhateverColumnYouWantHere
FROM Employee LEFT OUTER JOIN Role On Employee.Id = Role.EmployeeID
WHERE Employee.Id = #Id
If the employee isn't there then Read will return false. If the employee is there, but lacks a role, then Role.WhateverColumnYouWantHere will be NULL (IsDBNull will return true).
Additionally, you likely want to remove your for (int i = 0; i < roleIds.Length; i++) loop (leave the logic inside it - just remove the loop) since it isn't doing anything useful. Also, change if (reader.Read()) to while (reader.Read()) to handle the possibility of multiple roles. Plus, you likely should use reader.GetInt32(0) rather than Int32.Parse(reader.GetString((0)) - assuming that the Id is a 32-bit integer (rather than a string). Also, remove the , 32 code - it is unnecessary, since SqlDbType.Int has a fixed size (i.e. it knows it is 32-bits).

Get column name from SQL Server

I'm trying to get the column names of a table I have stored in SQL Server 2008 R2.
I've literally tried everything but I can't seem to find how to do this.
Right now this is my code in C#
public string[] getColumnsName()
{
List<string> listacolumnas=new List<string>();
using (SqlConnection connection = new SqlConnection(Connection))
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT TOP 0 * FROM Usuarios";
connection.Open();
using (var reader = command.ExecuteReader(CommandBehavior.KeyInfo))
{
reader.Read();
var table = reader.GetSchemaTable();
foreach (DataColumn column in table.Columns)
{
listacolumnas.Add(column.ColumnName);
}
}
}
return listacolumnas.ToArray();
}
But this is returning me the following
<string>ColumnName</string>
<string>ColumnOrdinal</string>
<string>ColumnSize</string>
<string>NumericPrecision</string>
<string>NumericScale</string>
<string>IsUnique</string>
<string>IsKey</string>
<string>BaseServerName</string>
<string>BaseCatalogName</string>
<string>BaseColumnName</string>
<string>BaseSchemaName</string>
<string>BaseTableName</string>
<string>DataType</string>
<string>AllowDBNull</string>
<string>ProviderType</string>
<string>IsAliased</string>
<string>IsExpression</string>
<string>IsIdentity</string>
<string>IsAutoIncrement</string>
<string>IsRowVersion</string>
<string>IsHidden</string>
<string>IsLong</string>
<string>IsReadOnly</string>
<string>ProviderSpecificDataType</string>
<string>DataTypeName</string>
<string>XmlSchemaCollectionDatabase</string>
<string>XmlSchemaCollectionOwningSchema</string>
<string>XmlSchemaCollectionName</string>
<string>UdtAssemblyQualifiedName</string>
<string>NonVersionedProviderType</string>
<string>IsColumnSet</string>
Any ideas?
It shows the <string> tags as this is how my web service sends the data.
You can use the query below to get the column names for your table. The query below gets all the columns for a user table of a given name:
select c.name from sys.columns c
inner join sys.tables t
on t.object_id = c.object_id
and t.name = 'Usuarios' and t.type = 'U'
In your code, it will look like that:
public string[] getColumnsName()
{
List<string> listacolumnas=new List<string>();
using (SqlConnection connection = new SqlConnection(Connection))
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = "select c.name from sys.columns c inner join sys.tables t on t.object_id = c.object_id and t.name = 'Usuarios' and t.type = 'U'";
connection.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
listacolumnas.Add(reader.GetString(0));
}
}
}
return listacolumnas.ToArray();
}
I typically use the GetSchema method to retrieve Column specific information, this snippet will return the column names in a string List:
using (SqlConnection conn = new SqlConnection("<ConnectionString>"))
{
string[] restrictions = new string[4] { null, null, "<TableName>", null };
conn.Open();
var columnList = conn.GetSchema("Columns", restrictions).AsEnumerable().Select(s => s.Field<String>("Column_Name")).ToList();
}
SELECT COLUMN_NAME
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = 'YourTable'
public string[] getColumnsName()
{
List<string> listacolumnas=new List<string>();
using (SqlConnection connection = new SqlConnection(Connection))
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = "select column_name from information_schema.columns where table_name = 'Usuarios'";
connection.Open(;
using (var reader = command.ExecuteReader(CommandBehavior.KeyInfo))
{
reader.Read();
var table = reader.GetSchemaTable();
foreach (DataColumn column in table.Columns)
{
listacolumnas.Add(column.ColumnName);
}
}
}
return listacolumnas.ToArray();
}
The original post was close to the goal, Just some small changes and you got it.
Here is my solution.
public List<string> GetColumns(string tableName)
{
List<string> colList = new List<string>();
DataTable dataTable = new DataTable();
string cmdString = String.Format("SELECT TOP 0 * FROM {0}", tableName);
if (ConnectionManager != null)
{
try
{
using (SqlDataAdapter dataContent = new SqlDataAdapter(cmdString, ConnectionManager.ConnectionToSQL))
{
dataContent.Fill(dataTable);
foreach (DataColumn col in dataTable.Columns)
{
colList.Add(col.ColumnName);
}
}
}
catch (Exception ex)
{
InternalError = ex.Message;
}
}
return colList;
}
Currently, there are two ways I could think of doing this:
In pure SQL Server SQL you can use the views defined in INFORMATION_SCHEMA.COLUMNS. There, you would need to select the row for your table, matching on the column TABLE_NAME.
Since you are using C#, it's probably easier to obtain the names from the SqlDataReader instance that is returned by ExecuteReader. The class provides a property FieldCount, for the number of columns, and a method GetName(int), taking the column number as its argument and returning the name of the column.
sp_columns - http://technet.microsoft.com/en-us/library/ms176077.aspx
There are many built in stored procedures for this type of thing.

Making a Webservice (asp.NET) which accepts several Paramters seperated by comma

I have the following Webservice and SQL-Query:
public class DIENSTLEISTUNG
{
public string DienstleistungName { get; set; }
public string DienstleistungArtBezeichnung { get; set; }
}
internal static List<DIENSTLEISTUNG> Dienstleistung(string RAUM_ID)
{
List<DIENSTLEISTUNG> BestuhlungObject = new List<DIENSTLEISTUNG>();
using (SqlConnection con = new SqlConnection(#"Data Source=Localhost\SQLEXPRESS;Initial Catalog=BOOK-IT-V2;Integrated Security=true;"))
using (SqlCommand cmd = new SqlCommand(#"
SELECT
DISTINCT dl.NAME AS NAME, da.BEZEICHNUNG AS BEZEICHNUNG
FROM RAUM r
RIGHT JOIN DIENSTLEISTUNG_Raum bs ON bs.RAUM_ID = (" + Room_ID + ")
RIGHT JOIN DIENSTLEISTUNG ba ON bs.DIENSTLEISTUNG_ID = ba.ID
RIGHT JOIN DIENSTLEISTUNGSART da ON ba.DIENSTLEISTUNGSART_ID = da.ID
RIGHT JOIN DIENSTLEISTER dl ON da.DIENSTLEISTER_ID = dl.ID", con))
{
con.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
if (rdr["NAME"] != DBNull.Value && rdr["BEZEICHNUNG"] != DBNull.Value)
{
BestuhlungObject.Add(new DIENSTLEISTUNG()
{
DienstleistungName = rdr["NAME"].ToString(),
DienstleistungArtBezeichnung = rdr["BEZEICHNUNG"].ToString()
});
}
}
}
}
return BestuhlungObject;
}
}
}
This Webservice is working like charm. I can send one Room_ID = 219 and get the expected output. My Question is, how can i send more then one Room_ID seperated by comma. For Example: Room_ID = 219, 220, 221
Can someone please help me with that?
Thanks in advance
See T-SQL stored procedure that accepts multiple Id values
One of many ways (MS SQL 2005+), if you can pass parameters as xml:
var sql =
#"SET ARITHABORT ON;
SELECT ...
RIGHT JOIN DIENSTLEISTUNG_Raum bs ON bs.RAUM_ID IN
(
SELECT tbl.col.value('.', 'varchar(20)')
FROM #xml.nodes('id') as tbl(col)
) ...";
SqlCommand cmd = new SqlCommand(sql, connection);
cmd.Parameters.Add("#xml", SqlDbType.Xml).Value = "<id>111</id><id>222</id><id>333</id>";
Or using LIKE if you can pass parameters as ,aaa,bbb,ccc, (note the order of LIKE arguments to avoid an injection)
var sql =
#"SELECT ...
RIGHT JOIN DIENSTLEISTUNG_Raum bs ON #ids LIKE '%,' + bs.RAUM_ID + ',%'
...";
SqlCommand cmd = new SqlCommand(sql, connection);
cmd.Parameters.Add("#ids", SqlDbType.VarChar).Value = ",111,222,333,";

How can I determine if column of a stored procedure result can be null

I'm writing a code generator and am getting stuck on determining the nullable status of a stored procedure result set Column. I can query the DataType just fine but neither the datareader object nor a data table column contain the correct nullable value of my column.
public List<DataColumn> GetColumnInfoFromStoredProcResult(string schema, string storedProcName)
{
//build sql text
var sb = new StringBuilder();
sb.Append("SET FMTONLY OFF; SET FMTONLY ON; \n");//this is how EF4.1 did so I copied..not sure why the repeat
sb.Append(String.Format("exec {0}.{1} ", schema, storedProcName));
var prms = GetStoredProcedureParameters(schema: schema, sprocName: storedProcName);
var count = 1;
foreach (var param in prms)
{
sb.Append(String.Format("{0}=null", param.Name));
if (count < prms.Count)
{
sb.Append(", ");
}
count++;
}
sb.Append("\n SET FMTONLY OFF; SET FMTONLY OFF;");
var dataTable = new DataTable();
//var list = new List<DataColumn>();
using (var sqlConnection = this.SqlConnection)
{
using (var sqlAdapter = new SqlDataAdapter(sb.ToString(), sqlConnection))
{
if (sqlConnection.State != ConnectionState.Open) sqlConnection.Open();
sqlAdapter.SelectCommand.ExecuteReader(CommandBehavior.KeyInfo);
sqlConnection.Close();
sqlAdapter.Fill(dataTable);
}
//using (var sqlCommand = new SqlCommand())
//{
// sqlCommand.CommandText = sb.ToString();
// sqlCommand.CommandType = CommandType.Text;
// sqlCommand.Connection = sqlConnection;
// if (sqlConnection.State != ConnectionState.Open) sqlConnection.Open();
// var dr = sqlCommand.ExecuteReader(CommandBehavior.SchemaOnly);
// var whateva = dr.GetSchemaTable();
// foreach (DataColumn col in whateva.Columns)
// {
// list.Add(col);
// }
//}
}
var list = dataTable.Columns.Cast<DataColumn>().ToList();
return list;
}
I'm trying to end up with something similar to the the Entities Framework creation of a complex type from a stored procedure. Can I hijack that functionality?
On this example the Id column.. tblJobId (not my naming convention) would never be null.. But I selected null as ImNull and it has all the same properties so how does EF determine if the corresponding C# data type should be nullable or not?
Has anybody done this..
Ideas are appreciated.
The secret was to use Schema Only and fill a dataset not datatable. Now the AllowDbNull property on the datacolumn properly displays the nullable status of the return value.
This was it...
public List<DataColumn> GetColumnInfoFromStoredProcResult(string schema, string storedProcName)
{
//build sql text
var sb = new StringBuilder();
sb.Append("SET FMTONLY OFF; SET FMTONLY ON; \n");//this is how EF4.1 did so I copied..not sure why the repeat
sb.Append(String.Format("exec {0}.{1} ", schema, storedProcName));
var prms = GetStoredProcedureParameters(schema: schema, sprocName: storedProcName);
var count = 1;
foreach (var param in prms)
{
sb.Append(String.Format("{0}=null", param.Name));
if (count < prms.Count)
{
sb.Append(", ");
}
count++;
}
sb.Append("\n SET FMTONLY OFF; SET FMTONLY OFF;");
var ds = new DataSet();
using (var sqlConnection = this.SqlConnection)
{
using (var sqlAdapter = new SqlDataAdapter(sb.ToString(), sqlConnection))
{
if (sqlConnection.State != ConnectionState.Open) sqlConnection.Open();
sqlAdapter.SelectCommand.ExecuteReader(CommandBehavior.SchemaOnly);
sqlConnection.Close();
sqlAdapter.FillSchema(ds, SchemaType.Source, "MyTable");
}
}
var list = ds.Tables[0].Columns.Cast<DataColumn>().ToList();
return list;
}
public List<SqlParamInfo> GetStoredProcedureParameters(string schema, string sprocName)
{
var sqlText = String.Format(
#"SELECT
[Name] = N'#RETURN_VALUE',
[ID] = 0,
[Direction] = 6,
[UserType] = NULL,
[SystemType] = N'int',
[Size] = 4,
[Precision] = 10,
[Scale] = 0
WHERE
OBJECTPROPERTY(OBJECT_ID(N'{0}.{1}'), 'IsProcedure') = 1
UNION
SELECT
[Name] = CASE WHEN p.name <> '' THEN p.name ELSE '#RETURN_VALUE' END,
[ID] = p.parameter_id,
[Direction] = CASE WHEN p.is_output = 0 THEN 1 WHEN p.parameter_id > 0 AND p.is_output = 1 THEN 3 ELSE 6 END,
[UserType] = CASE WHEN ut.is_assembly_type = 1 THEN SCHEMA_NAME(ut.schema_id) + '.' + ut.name ELSE NULL END,
[SystemType] = CASE WHEN ut.is_assembly_type = 0 AND ut.user_type_id = ut.system_type_id THEN ut.name WHEN ut.is_user_defined = 1 OR ut.is_assembly_type = 0 THEN st.name WHEN ut.is_table_type =1 Then 'STRUCTURED' ELSE 'UDT' END,
[Size] = CONVERT(int, CASE WHEN st.name IN (N'text', N'ntext', N'image') AND p.max_length = 16 THEN -1 WHEN st.name IN (N'nchar', N'nvarchar', N'sysname') AND p.max_length >= 0 THEN p.max_length/2 ELSE p.max_length END),
[Precision] = p.precision,
[Scale] = p.scale
FROM
sys.all_parameters p
INNER JOIN sys.types ut ON p.user_type_id = ut.user_type_id
LEFT OUTER JOIN sys.types st ON ut.system_type_id = st.user_type_id AND ut.system_type_id = st.system_type_id
WHERE
object_id = OBJECT_ID(N'{0}.{1}')
ORDER BY 2", schema, sprocName);
using (var sqlConnection = this.SqlConnection)
{
using (var sqlCommand = new SqlCommand())
{
if (sqlConnection.State != ConnectionState.Open) sqlConnection.Open();
sqlCommand.Connection = sqlConnection;
sqlCommand.CommandType = CommandType.Text;
sqlCommand.CommandText = sqlText;
var dr = sqlCommand.ExecuteReader();
var result = new List<SqlParamInfo>();
while (dr.Read())
{
if (Convert.ToString(dr["Name"]) != "#RETURN_VALUE")
{
result.Add(new SqlParamInfo(dr));
}
}
return result;
}
}
}
Assume, that every column which comes from SP can be null - this is a valid assumption because stored procedure - its a kind of data abstraction layer and thus its code can change but still produce valid results.
If column was non-nullable yesterday it means nothing for today. So - all the columns which come from SP resultsets are nullable by design.
Update.
Assuming that table t1 has column Id INT IDENTITY PRIMARY KEY
Your stored proc looks like this:
CREATE PROC p1
AS
BEGIN
SELECT Id FROM t1
END
So it will never return an Id = NULL, but this is the SP - an abstraction of data, so - tomorrow i'll modify it like this:
CREATE PROC p1
AS
BEGIN
SELECT Id FROM t1
UNION
SELECT NULL
END
So, now it returns NULL - think about this. The difference in understanding of data abstraction

Categories

Resources