Can I execute multiple queries and return their results executing a SqlCommand just once?
See SqlDataReader.NextResult (an SqlDataReader is returned from calling SqlCommand.ExecuteReader):
Advances the data reader to the next result [set], when reading the results of batch Transact-SQL statements.
Example:
string commandText = #"SELECT Id, ContactId
FROM dbo.Subscriptions;
SELECT Id, [Name]
FROM dbo.Contacts;";
List<Subscription> subscriptions = new List<Subscription>();
List<Contact> contacts = new List<Contact>();
using (SqlConnection dbConnection = new SqlConnection(#"Data Source=server;Database=database;Integrated Security=true;"))
{
dbConnection.Open();
using (SqlCommand dbCommand = dbConnection.CreateCommand())
{
dbCommand.CommandText = commandText;
using(SqlDataReader reader = dbCommand.ExecuteReader())
{
while(reader.Read())
{
subscriptions.Add(new Subscription()
{
Id = (int)reader["Id"],
ContactId = (int)reader["ContactId"]
});
}
// this advances to the next resultset
reader.NextResult();
while(reader.Read())
{
contacts.Add(new Contact()
{
Id = (int)reader["Id"],
Name = (string)reader["Name"]
});
}
}
}
}
Other examples:
C# Multiple Result Sets
Executing a Query That Returns Multiple Result Sets with SqlDataReader : SqlCommand Select « ADO.Net « C# / CSharp Tutorial
Create a Stored Procedure that has multiple selects, and fill the DataSet.
using (SqlConnection conn = new SqlConnection(connection))
{
DataSet dataset = new DataSet();
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = new SqlCommand("MyProcedure", conn);
adapter.SelectCommand.CommandType = CommandType.StoredProcedure;
adapter.Fill(dataset);
return dataset;
}
The returned dataset will have a DataTable in it's Tables array for each select in the stored procedure.
Tools like "dapper" make this very easy, regardless of whether you use ad-hoc text queries or stored procedures; for example:
using(var multi = conn.QueryMultiple(sql, args))
{
var customers = multi.Read<Customer>().AsList(); // first grid
var regionName = multi.ReadFirstOrDefault<string>(); // second grid
var addresses = multi.Read<Address>().AsList(); // third grid
// todo: use those things
}
Individual grids can also be read without buffering (as an open IEnumerable<T> over the reader itself) via the optional parameters to Read[<T>].
I am using a dictionary approach.
You can use Newton Json to convert it to json.
This way you are not tied to types and IDataRecord
public List<List<Dictionary<string, object>>> ExecuteSqlReader(string cmd, int commandTimeout = 30, CommandType commandType = CommandType.Text)
{
var sqlCmd = new SqlCommand(cmd);
var allRecord = new List<List<Dictionary<string, object>>>();
using (var connection = GetSqlConnection(commandTimeout, commandType, ref sqlCmd))
{
using (var reader = sqlCmd.ExecuteReader())
{
if (reader.HasRows)
{
var result = new List<Dictionary<string, object>>();
while (reader.Read())
{
result = GetTableRowData(reader);
}
allRecord.Add(result);
}
while (reader.NextResult())
{
if (reader.HasRows)
{
var result = new List<Dictionary<string, object>>();
while (reader.Read())
{
result = GetTableRowData(reader);
}
allRecord.Add(result);
}
}
}
}
return allRecord;
}
I call a sproc and get multiple result sets with object, so you end up with a
List<List<Dictionary<string, object>>>
In the multiResultsSet each results set is then
List<Dictionary<string, object>>
They can be cast to their types and transformed into the models as needed.
After you set up the sproc command with everything needed, pass it to this:
private static List<List<Dictionary<string, object>>> ProcessReader(SqlCommand command)
{
var tables = new List<List<Dictionary<string, object>>>();
using (var reader = command.ExecuteReader())
{
do
{
var table = new List<Dictionary<string, object>>();
while (reader.Read())
table.Add(Read(reader));
tables.Add(table);
} while (reader.NextResult());
}
return tables;
}
and Read() is fairly straight forward.
private static Dictionary<string, object> Read(IDataRecord reader)
{
var row = new Dictionary<string, object>();
for (var i = 0; i < reader.FieldCount; i++)
{
var val = reader[i];
row[reader.GetName(i)] = val == DBNull.Value ? null : val;
}
return row;
}
This is what i have been using for returning multiple result sets.
public abstract class BaseRepo
{
private string _connectionString;
protected BaseRepo(string connectionString)
{
_connectionString = connectionString;
}
private SqlConnection GetSqlConnection(int commandTimeout, CommandType commandType, ref SqlCommand sqlCmd)
{
var connection = new SqlConnection(_connectionString);
connection.Open();
sqlCmd.Connection = connection;
sqlCmd.CommandTimeout = commandTimeout;
sqlCmd.CommandType = commandType;
return connection;
}
protected int ExecuteSql(SqlCommand sqlCmd, int commandTimeout = 30, CommandType commandType = CommandType.Text)
{
using (var connection = GetSqlConnection(commandTimeout, commandType, ref sqlCmd))
{
return sqlCmd.ExecuteNonQuery();
}
}
protected IEnumerable<T> ExecuteSqlReader<T>(Func<IDataRecord, T> CreateObject, SqlCommand sqlCmd, int commandTimeout = 30, CommandType commandType = CommandType.Text)
{
using (var connection = GetSqlConnection(commandTimeout, commandType, ref sqlCmd))
{
using (var reader = sqlCmd.ExecuteReader())
return ExecuteReader(CreateObject, reader);
}
}
protected Tuple<IEnumerable<T1>, IEnumerable<T2>> ExecuteSqlReader<T1,T2>(Func<IDataRecord, T1> CreateObject1, Func<IDataRecord, T2> CreateObject2, SqlCommand sqlCmd, int commandTimeout = 30, CommandType commandType = CommandType.Text)
{
using (var connection = GetSqlConnection(commandTimeout, commandType, ref sqlCmd))
{
using (var reader = sqlCmd.ExecuteReader())
{
var result1 = ExecuteReader(CreateObject1, reader).ToList();
var result2 = ExecuteReader(CreateObject2, reader).ToList();
return Tuple.Create<IEnumerable<T1>, IEnumerable<T2>>(result1, result2);
}
}
}
protected Tuple<IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>> ExecuteSqlReader<T1, T2, T3>(Func<IDataRecord, T1> CreateObject1, Func<IDataRecord, T2> CreateObject2, Func<IDataRecord, T3> CreateObject3, SqlCommand sqlCmd, int commandTimeout = 30, CommandType commandType = CommandType.Text)
{
using (var connection = GetSqlConnection(commandTimeout, commandType, ref sqlCmd))
{
using (var reader = sqlCmd.ExecuteReader())
{
var result1 = ExecuteReader(CreateObject1, reader).ToList();
var result2 = ExecuteReader(CreateObject2, reader).ToList();
var result3 = ExecuteReader(CreateObject3, reader).ToList();
return Tuple.Create<IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>>(result1, result2, result3);
}
}
}
protected Tuple<IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>, IEnumerable<T4>> ExecuteSqlReader<T1, T2, T3, T4>(Func<IDataRecord, T1> CreateObject1, Func<IDataRecord, T2> CreateObject2, Func<IDataRecord, T3> CreateObject3, Func<IDataRecord, T4> CreateObject4, SqlCommand sqlCmd, int commandTimeout = 30, CommandType commandType = CommandType.Text)
{
using (var connection = GetSqlConnection(commandTimeout, commandType, ref sqlCmd))
{
using (var reader = sqlCmd.ExecuteReader())
{
var result1 = ExecuteReader(CreateObject1, reader).ToList();
var result2 = ExecuteReader(CreateObject2, reader).ToList();
var result3 = ExecuteReader(CreateObject3, reader).ToList();
var result4 = ExecuteReader(CreateObject4, reader).ToList();
return Tuple.Create<IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>, IEnumerable<T4>>(result1, result2, result3, result4);
}
}
}
private IEnumerable<T> ExecuteReader<T>(Func<IDataRecord, T> CreateObject, SqlDataReader reader)
{
while (reader.Read())
{
yield return CreateObject(reader);
}
reader.NextResult();
}
}
Then I just inherit it like so:
public class ReviewRepo : BaseRepo
{
public ReviewRepo(string connectionString) : base(connectionString) { }
public ReviewPageableResult GetAllReviews(string productType, string serviceType, int pageNumber, int itemsPerPage, string sortBy, string sortDirection)
{
var parameters = new List<SqlParameter>
{
new SqlParameter("ProductRefDescription", productType),
new SqlParameter("ServiceRefDescription", serviceType),
new SqlParameter("ZipCodes", "NULL"),
new SqlParameter("PageNumber", pageNumber),
new SqlParameter("ItemsPerPage", itemsPerPage),
new SqlParameter("SortBy", sortBy),
new SqlParameter("SortDirection", sortDirection)
};
var cmd = new SqlCommand("dbo.GetReviews");
cmd.Parameters.AddRange(parameters.ToArray());
var results = ExecuteSqlReader(CreateReview, CreateReviewPageableResult, cmd, commandType: CommandType.StoredProcedure);
var reviewResult = results.Item2.Single();
reviewResult.Items = results.Item1;
return reviewResult;
}
public ReviewPageableResult GetReviewsByZip(string productType, string serviceType, string zipCodes, int pageNumber, int itemsPerPage, string sortBy, string sortDirection)
{
var parameters = new List<SqlParameter>
{
new SqlParameter("ProductRefDescription", productType),
new SqlParameter("ServiceRefDescription", serviceType),
new SqlParameter("ZipCodes", zipCodes),
new SqlParameter("PageNumber", pageNumber),
new SqlParameter("ItemsPerPage", itemsPerPage),
new SqlParameter("SortBy", sortBy),
new SqlParameter("SortDirection", sortDirection)
};
var cmd = new SqlCommand("dbo.GetReviewsByZipCodes");
cmd.Parameters.AddRange(parameters.ToArray());
var results = ExecuteSqlReader(CreateReview, CreateReviewPageableResult, cmd, commandType: CommandType.StoredProcedure);
var reviewResult = results.Item2.Single();
reviewResult.Items = results.Item1;
return reviewResult;
}
private Review CreateReview(IDataRecord record)
{
return new Review
{
PageReviewId = (int)record["PageReviewId"],
ProductRefId = (Guid)record["ProductRefId"],
ServiceTypeRefId = Convert.IsDBNull(record["ServiceTypeRefId"]) ? Guid.Empty : (Guid)record["ServiceTypeRefId"],
TerritoryId = Convert.IsDBNull(record["TerritoryId"]) ? Guid.Empty : (Guid)record["TerritoryId"],
FirstName = $"{record["FirstName"]}",
LastName = $"{record["LastName"]}",
City = $"{record["City"]}",
State = $"{record["State"]}",
Answer = $"{record["Answer"]}",
Rating =(double)record["Rating"],
SurveyDate = (DateTime)record["SurveyDate"]
};
}
private ReviewPageableResult CreateReviewPageableResult(IDataRecord record)
{
return new ReviewPageableResult
{
AverageRating = (double)record["AverageRating"],
Count1Stars = (int)record["Count1Stars"],
Count2Stars = (int)record["Count2Stars"],
Count3Stars = (int)record["Count3Stars"],
Count4Stars = (int)record["Count4Stars"],
Count5Stars = (int)record["Count5Stars"],
ItemsPerPage = (int)record["ItemsPerPage"],
PageNumber = (int)record["PageNumber"],
TotalCount = (int)record["TotalCount"],
};
}
}
Try this
Dim dt1, dt2, dt3As New DataTable
Dim command As SqlCommand
Dim adapter As New SqlDataAdapter
Dim ds As New DataSet
Dim Sql1, Sql2, Sql3 As String
Sql1 = "select id, CurName from Table1 where IS_Deleted=0 order by id"
Sql2 = "select id ,Item from Table2 order by id"
Sql3 = "select id ,SellPrice from Table3 order by id"
Try
conn1.Open()
command = New SqlCommand(Sql1, conn1)
command.CommandType = CommandType.Text
adapter.SelectCommand = command
adapter.Fill(ds, "dt1")
adapter.SelectCommand.CommandText = Sql2
adapter.Fill(ds, "dt2")
adapter.SelectCommand.CommandText = Sql3
adapter.Fill(ds, "dt3")
adapter.Dispose()
command.Dispose()
conn1.Close()
cmbCurrency.DataSource = ds.Tables("dt1")
cmbCurrency.DisplayMember = "CurName"
cmbCurrency.ValueMember = "id"
cmbCurrency.SelectedIndex = -1
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''|
cmbGroups.DataSource = ds.Tables("dt2")
cmbGroups.DisplayMember = "Item"
cmbGroups.ValueMember = "id"
cmbGroups.SelectedIndex = -1
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''|
cmbUnits.DataSource = ds.Tables("dt3")
cmbUnits.DisplayMember = "SellPrice"
cmbUnits.ValueMember = "id"
cmbUnits.SelectedIndex = -1
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''|
Catch ex As Exception
MessageBox.Show(ex.ToString())
End Try
For More Help http://vb.net-informations.com/dataset/dataset-multiple-tables-sqlserver.htm
I have a class file where I declare readonly string of my query to be used in a method. I met the error of
Must declare the scalar variable "#DBID"
May I know if I declare my variables wrongly?
Below are the code snippets:
Class file:
private static readonly string QUERY_GETMATCHEDRECORD = "SELECT [Title], [ItemLink], [RecordDocID] FROM [ERMS].[dbo].[Records] WHERE [ID] = #DBID AND [V1RecordID] = #recID AND [V1RecordDocID] = #recDocID";
public DataTable GetMatchedRecord(string DBID, string recID, string recDocID)
{
string Method = System.Reflection.MethodBase.GetCurrentMethod().Name;
DataTable dt = new DataTable();
try
{
using (DB db = new DB(_datasource, _initialCatalog))
{
db.OpenConnection();
using (SqlCommand command = new SqlCommand())
{
string commandText = QUERY_GETMATCHEDRECORD .FormatWith(DBID,recID,recDocID);
_log.LogDebug(Method, "Command|{0}".FormatWith(commandText));
command.CommandText = commandText;
dt = db.ExecuteDataTable(command);
}
db.CloseConnection();
}
}
catch (Exception ex)
{
_log.LogError(Method, "Error while retrieving matching records |{0}".FormatWith(ex.Message));
_log.LogError(ex);
}
return dt;
}
Program .cs file:
MatchedRecords = oDB.GetMatchedRecord(DBID, RecID, RecDocID);
using '#'-notated variables will only work if you add the parameters to the commands parameter-collection.
try the following:
using (DB db = new DB(_datasource, _initialCatalog))
{
db.OpenConnection();
using (SqlCommand command = new SqlCommand())
{
command.CommandText = QUERY_GETMATCHEDRECORD;
command.Parameters.AddWithValue("#DBID", DBID);
command.Parameters.AddWithValue("#recID", recID);
command.Parameters.AddWithValue("#recDocID",recDocID);
dt = db.ExecuteDataTable(command);
}
db.CloseConnection();
}
I'm trying to get all data from an SQL table and store it in a List using the C# programming language.
the SQL statement I'm using is:
private string cmdShowEmployees = "SELECT * FROM Employees;";
This is being used in the same class as a function
public List<string> showAllIdData()
{
List<string> id = new List<string>();
using (sqlConnection = getSqlConnection())
{
sqlCommand.Connection = sqlConnection;
sqlCommand.CommandText = cmdShowEmployees;
SqlDataReader reader = sqlCommand.ExecuteReader();
while (reader.Read()) {
id.Add(reader[0].ToString());
}
return id;
}
}
and here
public List<string> showAllActiveData()
{
List<string> active = new List<string>();
using (sqlConnection = getSqlConnection())
{
sqlCommand.Connection = sqlConnection;
sqlCommand.CommandText = cmdShowEmployees;
SqlDataReader reader = sqlCommand.ExecuteReader();
while (reader.Read()) {
active.Add(reader[1].ToString());
}
return active;
}
I would have to create 9 more functions this way in order to get all the data out of the Employees table. This seems very inefficient and I was wondering if there was a more elegant way to do this.
I know using an adapter is one way to do it but I don't think it is possible to convert a filled adapter to a list, list list etc.
SqlDataAdapter adapter = sqlDataCollection.getAdapter();
DataSet dataset = new DataSet();
adapter.Fill(dataset, "idEmployees");
dataGridView1.DataSource = dataset;
dataGridView1.DataMember = "idEmployees";
Any ideas?
If you must use the reader in this way, why not create an object which holds the table row data.
public class SomeComplexItem
{
public string SomeColumnValue { get; set;}
public string SomeColumnValue2 { get; set;}
public string SomeColumnValue3 { get; set;}
public string SomeColumnValue4 { get; set;}
}
That way you can loop through with your reader as follows:
public List<SomeComplexItem> showAllActiveData()
{
List<SomeComplexItem> active = new List<SomeComplexItem>();
using (sqlConnection = getSqlConnection())
{
sqlCommand.Connection = sqlConnection;
sqlCommand.CommandText = cmdShowEmployees;
SqlDataReader reader = sqlCommand.ExecuteReader();
while (reader.Read())
{
var someComplexItem = new SomeComplexItem();
someComplexItem.SomeColumnValue = reader[1].ToString();
someComplexItem.SomeColumnValue2 = reader[2].ToString();
someComplexItem.SomeColumnValue3 = reader[3].ToString();
active.Add(someComplexItem);
}
return active;
}
You could use two select statements to populate two List<string> as shown in the example below where the key between reads is reader.NextResult();.
The database used is the standard Microsoft NorthWind database.
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
namespace SQL_Server_TwoList
{
public class DataOperations
{
public List<string> Titles { get; set; }
public List<string> Names { get; set; }
/// <summary>
/// Trigger code to load two list above
/// </summary>
public DataOperations()
{
Titles = new List<string>();
Names = new List<string>();
}
public bool LoadData()
{
try
{
using (SqlConnection cn = new SqlConnection(Properties.Settings.Default.ConnectionString))
{
string commandText = #"
SELECT [TitleOfCourtesy] + ' ' + [LastName] + ' ' + [FirstName] As FullName FROM [NORTHWND.MDF].[dbo].[Employees];
SELECT DISTINCT [Title] FROM [NORTHWND.MDF].[dbo].[Employees];";
using (SqlCommand cmd = new SqlCommand(commandText, cn))
{
cn.Open();
SqlDataReader reader = cmd.ExecuteReader();
// get results into first list from first select
if (reader.HasRows)
{
while (reader.Read())
{
Names.Add(reader.GetString(0));
}
// move on to second select
reader.NextResult();
// get results into first list from first select
if (reader.HasRows)
{
while (reader.Read())
{
Titles.Add(reader.GetString(0));
}
}
}
}
}
return true;
}
catch (Exception)
{
return false;
}
}
}
}
Form code
namespace SQL_Server_TwoList
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
DataOperations dataOps = new DataOperations();
if (dataOps.LoadData())
{
listBox1.DataSource = dataOps.Names;
listBox2.DataSource = dataOps.Titles;
}
}
}
}
You could always add it all to a dataset or datatable instead of looping through using datareader to add to an array, dataset allows you to access data in similar way to array anyway.
Connstr = "Data Source = " + SelectedIP + "; Initial Catalog = " + dbName + "; User ID = " + txtUsername.Text +"; Password = "+ txtPassword.Text +"";
conn = new SqlConnection(Connstr);
try
{
string contents = "SELECT * FROM ..."
conn.Open();
SqlDataAdapter da_1 = new SqlDataAdapter(contents, conn); //create command using contents of sql file
da_1.SelectCommand.CommandTimeout = 120; //set timeout in seconds
DataSet ds_1 = new DataSet(); //create dataset to hold any errors that are rturned from the database
try
{
//manipulate database
da_1.Fill(ds_1);
if (ds_1.Tables[0].Rows.Count > 0) //loop through all rows of dataset
{
for (int i = 0; i < ds_1.Tables[0].Rows.Count; i++)
{
//rows[rownumber][column number/ "columnName"]
Console.Write(ds_1.Tables[0].Rows[i][0].ToString() + " ");
}
}
}
catch(Exception err)
{}
conn.Close();
}
catch(Exception ex)
{}
I am using the following code to consume a CUBRID database java stored procedure.
string ConnectionString = "server=localhost;database=demodb;port=30000;user=dba;password=123456";
DataTable dt = new DataTable();
DataSet ds = new DataSet();
CUBRIDConnection con = new CUBRIDConnection(ConnectionString);
CUBRIDCommand com = new CUBRIDCommand();
com.CommandType = CommandType.StoredProcedure;
com.Connection = con;
com.CommandText = "select rset()";
CUBRIDParameter pan = new CUBRIDParameter();
pan.Direction = ParameterDirection.Output;
pan.CUBRIDDataType = CUBRIDDataType.CCI_U_TYPE_RESULTSET;
pan.ParameterName = "?p1";
CUBRIDDataAdapter dap = new CUBRIDDataAdapter(com);
con.Open();
int val = dap.Fill(ds);
con.Close();
and in the server use the next function and stored procedure in the server
public class JavaSP3 {
public static ResultSet TResultSet(){
try {
Class.forName("cubrid.jdbc.driver.CUBRIDDriver");
Connection con = DriverManager.getConnection("jdbc:default:connection:");
String sql = "select * from athlete";
Statement stmt=con.createStatement();
ResultSet rs = stmt.executeQuery(sql);
((CUBRIDResultSet)rs).setReturnable();
return rs;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
}
and the function code is this
CREATE FUNCTION "rset"() RETURN CURSOR
AS LANGUAGE JAVA
NAME 'JavaSP3.TResultSet() return cubrid.jdbc.driver.CUBRIDResultSet'
I run this with a function that result a string and return the value, but when I change to CUBRIDResultSet value dont work and CUBRID says>
execute error:-911
line 1 is not executed (error)
Error description:
Invalid call: it can not return ResultSet.
Please, I have 3 days trying to solve this any one can help me?
ADO.NET dont provide support for ResultSet.
http://www.cubrid.org/?mid=forum&category=195532&document_srl=358924
using System.Data;
using CUBRID.Data.CUBRIDClient;
using System.Data.Common;
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string ConnectionString = "server=localhost;database=demodb;port=30000;user=dba;password=123456";
DataTable dt = new DataTable();
DataSet ds = new DataSet();
CUBRIDConnection con = new CUBRIDConnection(ConnectionString);
CUBRIDCommand com = new CUBRIDCommand();
com.CommandType = CommandType.Text; //Important ADO.NET driver crash using call convention
com.Connection = con;
com.CommandText = "select rset();";
CUBRIDParameter pan = new CUBRIDParameter();
con.Open();
DbDataReader reader = com.ExecuteReader();
CustomAdapter da = new CustomAdapter();
da.FillFromReader(dt, reader);
con.Close();
DataRow fila = dt.Rows[0];
Console.WriteLine(fila[0].ToString());
Console.ReadKey();
}
}
public class CustomAdapter : System.Data.Common.DbDataAdapter
{
public int FillFromReader(DataTable dataTable, IDataReader dataReader)
{
return this.Fill(dataTable, dataReader);
}
protected override System.Data.Common.RowUpdatedEventArgs CreateRowUpdatedEvent(DataRow a, IDbCommand b, StatementType c, System.Data.Common.DataTableMapping d)
{
return (System.Data.Common.RowUpdatedEventArgs)new EventArgs();
}
protected override System.Data.Common.RowUpdatingEventArgs CreateRowUpdatingEvent(DataRow a, IDbCommand b, StatementType c, System.Data.Common.DataTableMapping d)
{
return (System.Data.Common.RowUpdatingEventArgs)new EventArgs();
}
protected override void OnRowUpdated(System.Data.Common.RowUpdatedEventArgs value)
{
}
protected override void OnRowUpdating(System.Data.Common.RowUpdatingEventArgs value)
{
}
}
java class
import java.sql.*;
import cubrid.jdbc.driver.*;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import javax.xml.transform.dom.*;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class JavaSP3 {
public static String TResultSet(){
ResultSet rs = null;
Statement stmt = null;
String sql;
try {
Class.forName("cubrid.jdbc.driver.CUBRIDDriver");
Connection con = DriverManager.getConnection("jdbc:default:connection:");
((CUBRIDConnection)con).setCharset("euc_kr");
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder =factory.newDocumentBuilder();
Document doc = builder.newDocument();
Element results = doc.createElement("Results");
doc.appendChild(results);
sql = "select * from athlete";
stmt=con.createStatement();
rs = stmt.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
int colCount = rsmd.getColumnCount();
while (rs.next()) {
Element row = doc.createElement("Row");
results.appendChild(row);
for (int ii = 1; ii <= colCount; ii++) {
String columnName = rsmd.getColumnName(ii);
Object value = rs.getObject(ii);
Element node = doc.createElement(columnName);
node.appendChild(doc.createTextNode(value.toString()));
row.appendChild(node);
}
}
String valor = getDocumentAsXml(doc);
return valor;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public static String getDocumentAsXml(Document doc)
throws TransformerConfigurationException, TransformerException {
DOMSource domSource = new DOMSource(doc);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
//transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,"yes");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.ENCODING,"ISO-8859-1");
transformer.setOutputProperty
("{http://xml.apache.org/xslt}indent-amount", "4");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
java.io.StringWriter sw = new java.io.StringWriter();
StreamResult sr = new StreamResult(sw);
transformer.transform(domSource, sr);
return sw.toString();
}
}
Cubrid function
CREATE FUNCTION "rset"() RETURN STRING
AS LANGUAGE JAVA
NAME 'JavaSP3.TResultSet() return java.lang.String'
This allow you get data from Java stored procedures in CUBRID using ADO.NET
I have a ugly code that can't be reused. I have many similar queries. I want to rewrite it with SqlParameterCollectionExtensions or other better ways. But I don't know about SqlParameterCollectionExtensions at all.
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
SqlConnection con = new SqlConnection(strCon);
con.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandText = "UPDATE Problem_DE SET ProbDesc = #ProbDesc, field_1 = #field_1, field_2 = #field_2, field_3 = #field_3, field_4 = #field_4, field_5 = #field_5, field_6 = #field_6, field_7 = #field_7 WHERE (ProbId = #ProbId)";
if (e.NewValues["ProbDesc"] == null)
cmd.Parameters.AddWithValue("#ProbDesc", DBNull.Value);
else
cmd.Parameters.AddWithValue("#ProbDesc", e.NewValues["ProbDesc"]);
if (e.NewValues["field_1"] == null)
cmd.Parameters.AddWithValue("#field_1", DBNull.Value);
else
cmd.Parameters.AddWithValue("#field_1", e.NewValues["field_1"]);
if (e.NewValues["field_2"] == null)
cmd.Parameters.AddWithValue("#field_2", DBNull.Value);
else
cmd.Parameters.AddWithValue("#field_2", e.NewValues["field_2"]);
if (e.NewValues["field_3"] == null)
cmd.Parameters.AddWithValue("#field_3", DBNull.Value);
else
cmd.Parameters.AddWithValue("#field_3", e.NewValues["field_3"]);
if (e.NewValues["field_4"] == null)
cmd.Parameters.AddWithValue("#field_4", DBNull.Value);
else
cmd.Parameters.AddWithValue("#field_4", e.NewValues["field_4"]);
\\ blah blah
cmd.ExecuteNonQuery();
con.Close();
}
The sql parameters come from e or textbox etc.
Thanks.
Maybe something like this? I assume the problem is that you have a variable number of values, depending on the problem table?
private void UpdateProblem(string problemName, string problemDescription, int problemId, object[] fieldValues)
{
SqlConnection con = null;
SqlCommand cmd = new SqlCommand();
StringBuilder sql = new StringBuilder();
int fieldCounter = 1;
// start building the sql statement
sql.AppendFormat("UPDATE {0} SET ProbDesc = #ProbDesc", problemName);
// add the 'description' parameter
cmd.Parameters.Add(new SqlParameter("#ProbDesc", problemDescription));
// add each field value to the update statement... the SqlParameter will infer the database type.
foreach(object fieldValue in fieldValues)
{
// add additional SET clauses to the statement
sql.AppendFormat(",field{0} = #field{0}", fieldCounter);
// add the field parameter to the command's collection
cmd.Parameters.Add(new SqlParameter(String.Format("#field{0}", fieldCounter), fieldValue));
fieldCounter++;
}
// finish up the SQL statement by adding the where clause
sql.Append(" WHERE (ProbId = #ProbId)");
// add the 'problem ID' parameter to the command's collection
cmd.Parameters.Add(new SqlParameter("#ProbId", problemId));
// finally, execute the SQL
try
{
con.Open();
cmd.Connection = con;
cmd.CommandText = sql.ToString();
cmd.ExecuteNonQuery();
}
catch(SqlException ex)
{
// do some exception handling
}
finally
{
if(con != null)
con.Dispose();
}
}
An example to call this code would be:
public void UpdateProblemDe()
{
int problemId = FetchCurrentProblemId();
string field1 = e.NewValues["field_1"];
string field2 = e.NewValues["field_2"];
string field3 = ddlField3.SelectedValue;
int field4 = Convert.ToInt32(e.NewValues["field_4"]);
string field5 = txtField5.Text;
DateTime field6 = DateTime.Now.AddSeconds(Convert.ToInt32(ddlField6.SelectedValue));
string field7 = txtField7.Text;
object[6] fieldValues;
if(field1 != null)
fieldValues[0] = field1;
else
fieldValues[0] = DBNull.Value;
if(field2 != null)
fieldValues[1] = field2;
else
fieldValues[1] = DBNull.Value
fieldValues[2] = field3;
fieldValues[3] = field4;
fieldValues[4] = field5;
fieldValues[5] = field6;
fieldValues[6] = field7;
UpdateProblem("Problem_DE", "Houston, we have a problem", problemId, fieldValues);
}
The example code above is obviously just a demonstration of how to make an array of objects stored from page control values and doesn't include any data validation that you will need to implement in production code.
If you won't know how big the object[] array needs to be at runtime, you can change it to be a generic List of objects and add the items dynamically.
Based on this answer
Create new SQLCommand's or reuse the same one
you could refactor your code the following way
public class DbHepler
{
private readonly string _connectionString;
public DbHepler(string connectionString)
{
_connectionString = connectionString;
}
public void ExecuteNonQuery(string query)
{
ExecuteNonQuery(query, null);
}
public void ExecuteNonQuery(string query, Dictionary<string, object> parameters)
{
using (SqlConnection conn = new SqlConnection(_connectionString))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = query;
if (parameters != null)
{
foreach (string parameter in parameters.Keys)
{
cmd.Parameters.AddWithValue(parameter, parameters[parameter] ?? DBNull.Value);
}
}
cmd.ExecuteNonQuery();
}
conn.Close();
}
}
}
your code will look something like:
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
string query = "UPDATE Problem_DE SET ProbDesc = #ProbDesc, field_1 = #field_1, field_2 = #field_2, field_3 = #field_3, field_4 = #field_4, field_5 = #field_5, field_6 = #field_6, field_7 = #field_7 WHERE (ProbId = #ProbId)";
Dictionary<string, object> parameters = new Dictionary<string, object>();
if (e.NewValues["ProbDesc"] == null)
parameters.Add("#ProbDesc", null);
else
parameters.Add("#ProbDesc", e.NewValues["ProbDesc"]);
//blah blah
DbHepler dbHepler = new DbHepler("your sql connection info");
dbHepler.ExecuteNonQuery(query, parameters);
}