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 am getting this error while i am trying to retrieve data from table.,
I am getting error at every line in while(r1.read()) loop., if i remove that line then i am getting same error in next line, it continues till last line of loop..
Please help.,
void otherdata()
{
if (conn.State == ConnectionState.Closed) conn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
cmd.CommandText = "select customer.cust_name,customer.cust_id,purchase_details.purchase_id,purchase_details.pdate,purchase_details.subtotal,purchase_details.total,purchase_details.supp_bill_id from Purchase_details inner join customer on purchase_details.supplier_id=customer.cust_id where id =" + pd;
SqlDataReader r1 = cmd.ExecuteReader();
while (r1.Read())
{
cbsupplier.Text = r1["cust_name"].ToString();
txtdate.Value = Convert.ToDateTime(r1["pdate"]);
txtsubtotal.Text = r1["subtotal"].ToString();
custid.Text = r1["cust_id"].ToString();
MessageBox.Show("pochalo");
}
r1.Close();
conn.Close();
if (conn.State == ConnectionState.Closed) conn.Open();
cmd.CommandText = "select * from purchase where purchase_id =" + pd;
r1 = cmd.ExecuteReader();
while (r1.Read())
{
txtadjust.Text = r1["adjustment"].ToString();
cbtaxrate.Text = r["taxrate"].ToString();
txttax.Text = r["tax"].ToString();
}
conn.Close();
r1.Close();
}
for your exception, i'm guessing is throwing this exception at this line :
cbtaxrate.Text = r["taxrate"].ToString();
txttax.Text = r["tax"].ToString();
because r["taxrate"] is not the same reader as r1["adjustment"]. So, i'm guessing you opened a reader with a name r in the same scope, then closed it, and opened a new reader r1 and did the above code. the issue here is not about closing the reader connection, it's about following the best practices in handling instances and naming conversion. if you chose a readable naming for your variables, it will be easer for you to read and follow the code.
You need also to use using clause on disposable objects, for a better disposal handling.
Here is a helper method that would saves you the hassle:
public static class SqlConnectionHelper
{
public static IEnumerable<KeyValuePair<string , object>> GetQueryValues(this SqlConnection connection , string sql , SqlParameter[] parameters , string[] fields)
{
if(connection == null)
{
throw new ArgumentNullException(nameof(connection));
}
var mappedFields = new Dictionary<int, string>();
using(var command = new SqlCommand(sql , connection))
{
if(parameters?.Length > 0)
{
command.Parameters.AddRange(parameters);
}
if(connection.State == ConnectionState.Closed)
connection.Open();
using(var reader = command.ExecuteReader())
{
if(reader.HasRows)
yield break;
if(fields?.Length > 0)
{
for(int x = 0; x < reader.FieldCount; x++)
{
var columnName = reader.GetName(x);
if(Array.Exists(fields , i => i.Equals(columnName , StringComparison.OrdinalIgnoreCase)))
{
mappedFields.Add(x , columnName);
}
}
while(reader.Read())
{
foreach(var field in mappedFields)
{
yield return new KeyValuePair<string , object>(field.Value , reader.GetValue(field.Key));
}
}
}
else
{
while(reader.Read())
{
for(int x = 0; x < reader.FieldCount; x++)
{
yield return new KeyValuePair<string , object>(reader.GetName(x) , reader.GetValue(x));
}
}
}
}
}
}
public static Dictionary<string , object> GetQueryUniqueValues(this SqlConnection connection , string sql , SqlParameter[] parameters , string[] fields)
{
return GetQueryValues(connection , sql , parameters , fields)
.GroupBy(x => x.Key)
.Select(x => new
{
Name = x.Key ,
Value = x.FirstOrDefault(s => s.Key == x.Key).Value
})
.ToDictionary(x => x.Name , x => x.Value);
}
}
with the reader helper, you can provide fields to get selected columns values, or you can just pass null to it and it will read all columns that have been provided under the SELECT statement.
reusing this to your current code would be like :
using(var connection = new SqlConnection(connectionString))
{
const string purchaseDetailsSql = "SELECT c.cust_name, c.cust_id, p.purchase_id, p.pdate, p.subtotal, p.total, p.supp_bill_id FROM Purchase_details p INNER JOIN customer c ON p.supplier_id = c.cust_id WHERE id = #id ;";
const string purchasesSql = "SELECT adjustment, taxrate, tax FROM purchase WHERE purchase_id = #id ;";
var parameters = new[]
{
new SqlParameter("#id", pd)
{
SqlDbType = SqlDbType.Int
}
};
var fields = new[] { "cust_name", "pdate" , "subtotal", "cust_id" };
// here would select the columns from the provided fields array.
var purchaseDetails = connection.GetQueryUniqueValues(purchaseDetailsSql , parameters, new[] { "cust_name", "pdate" , "subtotal", "cust_id" });
// here would select the columns from the query.
var purchases = connection.GetQueryUniqueValues(purchasesSql, parameters, null);
cbsupplier.Text = purchaseDetails["cust_name"]?.ToString();
txtdate.Value = Convert.ToDateTime(purchaseDetails["pdate"]);
txtsubtotal.Text = purchaseDetails["subtotal"]?.ToString();
custid.Text = purchaseDetails["cust_id"]?.ToString();
MessageBox.Show("pochalo");
txtadjust.Text = purchases["adjustment"]?.ToString();
cbtaxrate.Text = purchases["taxrate"]?.ToString();
txttax.Text = purchases["tax"]?.ToString();
}
I have a method for getting data out of my SQL Server database. I'm using a reader to get all the data. The problem is that the reader keeps reading and the application doesn't pop up. It is like an infinite loop or something.
public static List<Reservering> GetReserverings()
{
Reservering res = new Reservering();
using (var conn = new SqlConnection(ConnectionString))
{
conn.Open();
const string query = "select b.boekingid, k.naam, bk.incheckdatum, bk.uitcheckdatum, b.hotelid, b.aantal_gasten from boeking b join klant k on k.klantid = b.boekingid join boekingkamer bk on b.boekingid = bk.boekingid where bk.incheckdatum is not null and bk.uitcheckdatum is not null";
SqlCommand selectReserveringen = new SqlCommand(query, conn);
SqlDataReader reader = selectReserveringen.ExecuteReader();
while (reader.Read())
{
res.Id = (int)reader["boekingid"];
res.Naam = (string)reader["naam"];
res.Incheck_datum = (DateTime)reader["incheckdatum"];
res.Uitcheck_datum = (DateTime)reader["uitcheckdatum"];
res.Hotel = (int)reader["hotelid"];
res.Aantal_personen = (int)reader["aantal_gasten"];
}
reader.Close();
}
return GetReserverings();
}
Does anyone know how to fix this problem?
You've got an infinite recursion by calling the method itself at the end:
return GetReserverings();
You could've discovered this by setting a breakpoint in your method and stepping through your code.
You want to return a list of reservations instead:
var result = new List<Reservering>();
// your code...
return result;
And within your while() loop, you'd want to instantiate a new Reservering each iteration, and Add it to the result list.
You should create an instance of Reservering for each record read and store these instances in the List<Reservering>:
public static List<Reservering> GetReserverings() {
List<Reservering> result = new List<Reservering>();
using (var conn = new SqlConnection(ConnectionString)) {
conn.Open();
const string query =
#"select b.boekingid,
k.naam,
bk.incheckdatum,
bk.uitcheckdatum,
b.hotelid,
b.aantal_gasten
from boeking b join
klant k on k.klantid = b.boekingid join
boekingkamer bk on b.boekingid = bk.boekingid
where bk.incheckdatum is not null
and bk.uitcheckdatum is not null";
using (SqlCommand selectReserveringen = new SqlCommand(query, conn)) {
using (SqlDataReader reader = selectReserveringen.ExecuteReader()) {
while (reader.Read()) {
Reservering res = new Reservering();
result.Add(res);
res.Id = Convert.ToInt32(reader["boekingid"]);
res.Naam = Convert.ToString(reader["naam"]);
res.Incheck_datum = Convert.ToDateTime(reader["incheckdatum"]);
res.Uitcheck_datum = Convert.ToDateTime(reader["uitcheckdatum"]);
res.Hotel = Convert.ToInt32(reader["hotelid"]);
res.Aantal_personen = Convert.ToInt32(reader["aantal_gasten"]);
}
}
}
}
return result;
}
Edit: You can try to simplify while loop with a help of object initializing:
...
while (reader.Read()) {
result.Add(new Reservering() {
Id = Convert.ToInt32(reader["boekingid"]),
Naam = Convert.ToString(reader["naam"]),
Incheck_datum = Convert.ToDateTime(reader["incheckdatum"]),
Uitcheck_datum = Convert.ToDateTime(reader["uitcheckdatum"]),
Hotel = Convert.ToInt32(reader["hotelid"]),
Aantal_personen = Convert.ToInt32(reader["aantal_gasten"])
});
}
public static List<Reservering> GetReserverings()
{
List<Reserving> reservings = new List<Reservings>();
using (var conn = new SqlConnection(ConnectionString))
{
conn.Open();
const string query = "select b.boekingid, k.naam, bk.incheckdatum, bk.uitcheckdatum, b.hotelid, b.aantal_gasten from boeking b join klant k on k.klantid = b.boekingid join boekingkamer bk on b.boekingid = bk.boekingid where bk.incheckdatum is not null and bk.uitcheckdatum is not null";
SqlCommand selectReserveringen = new SqlCommand(query, conn);
SqlDataReader reader = selectReserveringen.ExecuteReader();
while (reader.Read())
{
Reservering res = new Reservering();
res.Id = (int)reader["boekingid"];
res.Naam = (string)reader["naam"];
res.Incheck_datum = (DateTime)reader["incheckdatum"];
res.Uitcheck_datum = (DateTime)reader["uitcheckdatum"];
res.Hotel = (int)reader["hotelid"];
res.Aantal_personen = (int)reader["aantal_gasten"];
reservings.add(res);
}
reader.Close();
}
return reservings;
}
I have a string array which consists of identifiers. I want to get some values from SQL using these identifiers . Is there a way of adding them with a string value to SqlCommand parameters?
I want to create a query like:
select CaseList from MasterReportData where Id = 1 OR Id = 2 OR Id = 3
This is my C# code:
public static List<string> GetCaseList(string[] masterIdList)
{
try
{
string query = " select CaseList from MasterReportData where #masterId";
SqlConnection conn = new SqlConnection(connString);
SqlCommand cmd = new SqlCommand(query, conn);
cmd.Parameters.AddWithValue("masterId", ***);
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
list.Add(reader[0].ToString());
}
}
conn.Close();
}
catch (Exception e)
{
var err= 0;
}
return list;
}
There are many different ways you can go about doing this but I prefer to create a temp table of possible values. That way you can do something like
select CaseList from MasterReportData where Id IN(select Id from tempTable)
The best approach (with sql optimization) would be:
Create your Type:
CREATE TYPE dbo.IntTTV AS TABLE
( Id int )
Your Ids:
var ids = new List<int>
{
1,
2,
3,
}
Create a schema:
var tableSchema = new List<SqlMetaData>(1)
{
new SqlMetaData("Id", SqlDbType.Int) // I think it's Int
}.ToArray();
Create the table in C#
var table = ids
.Select(i =>
{
var row = new SqlDataRecord(tableSchema);
row.SetInt32(0, i);
return row;
})
.ToList();
Create the SQL Parameter
var parameter = new SqlParameter();
parameter.SqlDbType = SqlDbType.Structured;
parameter.ParameterName = "#Ids";
parameter.Value = table;
parameter.TypeName = "dbo.IntTTV";
var parameters = new SqlParameter[1]
{
parameter
};
Slightly change your query (this is just an example:)
string query = "select mrd.CaseList from MasterReportData mrd"
+ " inner join #ids i on mrd.Id = i.id";
public static List<string> GetCaseList(string[] masterIdList)
{
List<string> list = new List<string>();
try
{
string query = "select CaseList from MasterReportData where ";
using (SqlConnection conn = new SqlConnection(connString))
{
int i = 0;
SqlCommand cmd = new SqlCommand(query, conn);
for(i = 0; i < masterIdList.Length; i++)
{
var parm = "#ID" + i;
cmd.Parameters.Add(new SqlParameter(parm, masterIdList[i]));
query += (i > 0 ? " OR " : "") + " Id = " + parm;
}
cmd.CommandText = query;
//cmd.Parameters.AddWithValue("masterId", ***);
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
list.Add(reader[0].ToString());
}
}
}
}
catch (Exception e)
{
e.ToString();
}
return list;
}
I want to build a custom interface (a separate aspx page) to manage the data that is put into the webforms for marketeers (WFFM) database, and that for just one form. It must be possible to edit the data and select records with particular sortings and pagings. The database is configured to be SQLite.
Is this possible and recommended, or is it just plain xml that is saved into the WFFM database? And how should I go about it?
This is completely doable, though the select query to get data out of WFFM is a bit funky because everything is stored loose in one huge table called "field" with only a trail of GUIDs to tie the stored values back to what form they came from and what field.
Provided below is part of an Export to Excel utility I wrote for WFFM data. It builds a DataTable object from submitted form results. You could adapt it to some other structure without much work though.
public string connectionStringWFFM = "user id=sitecore_admin;password=xxx;Data Source=SitecoreDBServer.com;Database=Sitecore_WebForms";
protected DataTable BuildDataTable(Item formItem)
{
List<FormResult> formResults = FormResults(formItem.ID.Guid);
List<Field> distinctFields = DistinctFields(formItem.ID.Guid);
var dt = new DataTable();
dt.Columns.Add("Submission_DateTime", typeof (string));
foreach (Field field in distinctFields)
{
var dataColumn = new DataColumn("_" + field.id.ToString("N"), typeof (string));
dataColumn.Caption = field.name.Replace(" ", "_");
dt.Columns.Add(dataColumn);
}
foreach (FormResult formResult in formResults)
{
var connection = new SqlConnection();
connection.ConnectionString = connectionStringWFFM;
var command = new SqlCommand();
command.Connection = connection;
command.CommandText = "select fieldid, value from field where formid=#formid order by fieldid";
command.Parameters.Add("#formid", SqlDbType.UniqueIdentifier).Value = formResult.id;
connection.Open();
SqlDataReader reader = command.ExecuteReader();
DataRow dataRow = dt.NewRow();
dataRow["Submission_DateTime"] = formResult.timestamp.ToString("MM/dd/yyyy HH:mm:ss");
while (reader.Read())
{
dataRow["_" + reader.GetGuid(0).ToString("N")] = reader.GetValue(1).ToString().Replace("<item>", "").Replace("</item>", "");
}
dt.Rows.Add(dataRow);
reader.Close();
connection.Close();
}
return dt;
}
public List<Field> DistinctFields(Guid formitemid)
{
var connection = new SqlConnection();
connection.ConnectionString = connectionStringWFFM;
var command = new SqlCommand();
command.Connection = connection;
command.CommandText = "select distinct fieldid from field where formid in (select id from form where formitemid=#formitemid) order by fieldid";
command.Parameters.Add("#formitemid", SqlDbType.UniqueIdentifier).Value = formitemid;
connection.Open();
SqlDataReader reader = command.ExecuteReader();
var results = new List<Field>();
int count = 0;
while (reader.Read())
{
var field = new Field();
field.id = reader.GetGuid(0);
Database database = Factory.GetDatabase("master");
Item i = database.GetItem(new ID(field.id));
if (i != null && i.DisplayName != null)
{
field.name = i.DisplayName;
}
else
{
field.name = "Field" + count;
}
results.Add(field);
count += 1;
}
reader.Close();
connection.Close();
return results;
}
public List<FormResult> FormResults(Guid formitemid)
{
var connection = new SqlConnection();
connection.ConnectionString = connectionStringWFFM;
var command = new SqlCommand();
command.Connection = connection;
command.CommandText = "select id, timestamp from form where formitemid=#formitemid";
command.Parameters.Add("#formitemid", SqlDbType.UniqueIdentifier).Value = formitemid;
connection.Open();
SqlDataReader reader = command.ExecuteReader();
var results = new List<FormResult>();
while (reader.Read())
{
var result = new FormResult();
result.id = reader.GetGuid(0);
result.timestamp = reader.GetDateTime(1);
results.Add(result);
}
reader.Close();
connection.Close();
return results;
}
public class FormResult
{
public Guid id { get; set; }
public DateTime timestamp { get; set; }
}
public class Field
{
public Guid id { get; set; }
public string name { get; set; }
}