Get SQL query result in Datatable using Servicestack ormlite - c#

I am new to Servicestack Ormlite.
I want to execute the SQL query on database using Servicestack Ormlite and get the results in datatable.
SQL query will be generated randomly, containing different tables, columns each time. So I can't use poco class for the same.
We are using SQL Server as the database.

OrmLite doesn't support or have any dependencies on DataTables or DataSets which as a code-first POCO ORM is strictly opposed against the use of.
See the Dynamic Result Set docs for examples of querying untyped structures, either in a object List:
db.Select<List<object>>(db.From<Poco>()
.Select("COUNT(*), MIN(Id), MAX(Id)"));
Or Dictionary:
db.Select<Dictionary<string,object>>(db.From<Poco>()
.Select("COUNT(*) Total, MIN(Id) MinId, MAX(Id) MaxId"));

you can use CreateCommand method to get a datareader, like this:
var dt = new DataTable();
using (var db = dbFactory.Open())
using (var cmd = db.CreateCommand())
{
cmd.CommandText = "select * from [table]";
cmd.CommandType = CommandType.Text;
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var row = dt.NewRow();
for (int i = 0; i < reader.FieldCount; i++)
{
if (dt.Columns == null || dt.Columns.Count == 0)
{
for (int j = 0; j < reader.FieldCount; j++)
{
dt.Columns.Add(reader.GetName(j), reader.GetFieldType(j));
}
}
var cell = reader.GetValue(i);
row[i] = cell;
}
dt.Rows.Add(row);
}
}
}

Related

Stored procedure returns multiple temp table results. I want to copy them into one CSV file using C#

I have a stored procedure that has multiple select statements using temp tables. I want to copy the results into one CSV file. Each result has different columns. I would like to copy them in such a way that each result set should leave two lines of space in CSV file.
Example below :
Sample stored procedure
Create procedure usp_Test_CSV_Report
As
Begin
select 'Text Sample' as Description, 123 Amount, 20210511 as Joindate
select GETDATE() as MonthATB
select 1 as AccountId, 'CI' as Name
select 'Sample Report'
End
The temp tables have been created within the stored procedure which will be called like Select * from #temp. I have not included real stored procedure which is vast.
I will be running the stored procedure using C#
string query = "EXEC alpha.dbo.usp_Test_CSV_Report";
SqlCommand cmd = new SqlCommand(query, SQLConnection);
SQLConnection.Open();
DataTable d_table = new DataTable();
SqlDataReader sqlReader = cmd.ExecuteReader();
while (sqlReader.Read())
{
d_table.Load(sqlReader);
// Write the Header Row to File
int ColumnCount = d_table.Columns.Count;
for (int ic = 0; ic < ColumnCount; ic++)
{
//MessageBox.Show(d_table.Columns[ic].ToString());
sw.Write(d_table.Columns[ic]);
if (ic < ColumnCount - 1)
{
sw.Write(FileDelimiter);
}
}
sw.Write(sw.NewLine);
// Write All Rows to the File
foreach (DataRow dr in d_table.Rows)
{
for (int ir = 0; ir < ColumnCount; ir++)
{
if (!Convert.IsDBNull(dr[ir]))
{
sw.Write(dr[ir].ToString());
//MessageBox.Show(dr[ir].ToString());
}
if (ir < ColumnCount - 1)
{
sw.Write(FileDelimiter);
}
}
sw.Write(sw.NewLine);
}
}
sqlReader.NextResult();
while (sqlReader.Read())
{
d_table.Load(sqlReader);
// Write the Header Row to File
int ColumnCount = d_table.Columns.Count;
for (int ic = 0; ic < ColumnCount; ic++)
{
//MessageBox.Show(d_table.Columns[ic].ToString());
sw.Write(d_table.Columns[ic]);
if (ic < ColumnCount - 1)
{
sw.Write(FileDelimiter);
}
}
sw.Write(sw.NewLine);
// Write All Rows to the File
foreach (DataRow dr in d_table.Rows)
{
for (int ir = 0; ir < ColumnCount; ir++)
{
if (!Convert.IsDBNull(dr[ir]))
{
sw.Write(dr[ir].ToString());
//MessageBox.Show(dr[ir].ToString());
}
if (ir < ColumnCount - 1)
{
sw.Write(FileDelimiter);
}
}
sw.Write(sw.NewLine);
}
}
SQLConnection.Close();
sw.Close();
So far I have tried this but this is not working!!
Any help?
I maintain a nuget package, Sylvan.Data.Csv, that makes this very easy.
string query = "EXEC alpha.dbo.usp_Test_CSV_Report";
using SqlConnection conn = GetSqlConnection();
conn.Open();
using SqlCommand cmd = new SqlCommand(query, conn);
using var sw = File.CreateText("usp_Test_CSV_Report.csv");
using var csvWriter = CsvDataWriter.Create(sw);
using var sqlReader = cmd.ExecuteReader();
bool first = true;
do
{
if (!first)
{
// write the two lines to separate the result sets.
sw.WriteLine();
sw.WriteLine();
}
first = false;
csvWriter.Write(sqlReader);
} while (sqlReader.NextResult());
The library also supports reading multiple result sets out of a single CSV in much the same way:
// tell the reader to expect multiple result sets.
var csvOpts = new CsvDataReaderOptions { ResultSetMode = ResultSetMode.MultiResult };
var csvReader = CsvDataReader.Create("usp_Test_CSV_Report.csv", csvOpts);
do
{
while (csvReader.Read())
{
for(int i = 0; i < csvReader.FieldCount; i++)
{
var value = csvReader.GetString(i);
}
}
} while (csvReader.NextResult());

using Oracle Exadata and C#: Paging data from Oracle to retrieve in datatable

I am using Oracle Exadata as database and using that in a ASP.NET C# Web application.
I am trying to query the data from the database and fetch the data in data table. The data is too huge as I am using a select * option. The data table errors out with memory issues and would not be the right approach as well.
I am trying to check if a paging model can be applied.
I have used the below code model with MS SQL, which works. I am not sure how this can be applied in Oracle query. Below is the code for MS SQL.
public List<DataTable> GetDataSet()
{
var dataTables = new List<DataTable>();
var totalRecords = 0;
var tableIndex = 1;
using (var cn = new SqlConnection {ConnectionString = ConnectionString})
{
using (var cmd = new SqlCommand {Connection = cn})
{
var selectStatement =
#"SELECT Cust.CustomerIdentifier,
Cust.CompanyName,
Cust.ContactName,
C.[Name] AS Country
FROM dbo.Customers AS Cust
INNER JOIN dbo.Countries AS C
ON Cust.CountryIdentifier = C.CountryIdentifier
ORDER BY Cust.CustomerIdentifier
OFFSET #Offset ROWS
FETCH NEXT 25 ROWS ONLY;";
var countStatement = "SELECT COUNT(Cust.CustomerIdentifier) FROM dbo.Customers AS Cust";
cmd.CommandText = countStatement;
cn.Open();
totalRecords = Convert.ToInt32(cmd.ExecuteScalar());
cmd.CommandText = selectStatement;
cmd.Parameters.Add("#OffSet", SqlDbType.Int);
for (var index = 0; index < totalRecords; index++)
{
if (index % 25 == 0)
{
cmd.Parameters["#OffSet"].Value = index;
var dt = new DataTable() {TableName = $"Table{tableIndex}"};
dt.Load(cmd.ExecuteReader());
dataTables.Add(dt);
tableIndex += 1;
}
}
}
}
return dataTables;
}
I am trying to achieve the same functionality with Oracle. How to query the Oracle to get the data in this same way. Thanks

Writing Sql Update method

public static int SQLUpdate(string sql, string[] names, object[] values)
{
if (names.Length != values.Length)
{
throw new ArgumentException("name/value mismatch");
}
using (var sqlconn = new SqlConnection(GetConnectionString))
{
sqlconn.Open();
using (var cmd = new SqlCommand(sql, sqlconn))
{
for (int i = 0; i < names.Length; i++)
{
cmd.Parameters.AddWithValue(names[i], values[i]);
}
return cmd.ExecuteNonQuery();
}
}
I wrote method to create Update command.
For example I have a Picture table in my SQL Server database with PictureID, UserID columns.
And user can add 3 pictures at once. You see values is array.
But in my example value[i] also is array. (3 pictures).
How can I write my SQLUpdate method for this ?
I think you are almost there except I would switch your code around a little so:
sqlconn.Open();
for (int i = 0; i < names.Length; i++)
{
using (var cmd = new SqlCommand(sql, sqlconn))
{
cmd.Parameters.AddWithValue(names[i], values[i]);
return cmd.ExecuteNonQuery();
}
}
**AS you are declaring a new SQLCommand everytime you may need to do cmd.Close() and cmd.Dispose() each time.
I think you need to pass data table in SQL procedure
http://www.codeproject.com/Tips/214492/Passing-a-datatable-to-a-stored-procedure-in-Sql-S

How to obtain the underlying SQL types for query results in .NET/C#?

For example, the following code prints "System.Int32", not "int":
string connArgs = "..."; // use your settings here
string query = "SELECT 1";
using (SqlConnection conn = new SqlConnection(connArgs)) {
conn.Open();
SqlCommand cmd = new SqlCommand(query, conn);
using (SqlDataReader reader = cmd.ExecuteReader())
for (int col = 0; col < reader.VisibleFieldCount; ++col)
Console.WriteLine(reader.GetFieldType(col));
}
How can I obtain the underlying SQL type, not just its equivalent .NET system type?
You can use a GetDataTypeName method for that:
Gets a string representing the data type of the specified column.
for (int col = 0; col < reader.VisibleFieldCount; ++col) {
Console.WriteLine(reader.GetDataTypeName(col));
}

Querying OLAP server

I use the following code to execute a query in C#:
AdomdConnection con = new AdomdConnection("Datasource=local;...");
con.Open();
AdomdCommand command = con.CreateCommand();
command.CommandText = input;
AdomdDataReader reader = command.ExecuteReader();
while (reader.Read())
{
for(i =0; i<reader.fieldCount; i++){
a[i]=reader.GetString(i);
}
return a;
Howeever, this code returns the full path in the hierarchy for each cell. I.e., each row of data is like [AllGeography, Canada, Vancouver, Allproduct, bikes, accessories, 297483].
I want to retrieve only the leaves and the measure value that is :[vancouver, accessories, 297483]. What should I do? How I can specify the leaves?
Because the result of MDX query is actually multidimentional, i feel myself more comfortable with ExecuteCellSet. You can get the whole CellSet, then you get Measures via coordinates.
For example (if you have one measure in query):
AdomdCommand cmd = conn.CreateCommand();
cmd.CommandText = #"SELECT
[Geography].[Geography].[Country].&[Canada].Children ON 0,
[Product].[Id] ON 1
FROM [Cube]
WHERE [Measures].[Your Measure]";
CellSet cs = cmd.ExecuteCellSet();
TupleCollection CanadaChildren = cs.Axes[0].Set.Tuples;
TupleCollection ProductIds = cs.Axes[1].Set.Tuples;
for (int row = 0; row < CanadaChildren.Count; row++)
{
for (int col = 0; col < ProductIds.Count; col++)
{
a[i++] = cs.Cells[col, row].Value;
}
}
conn.Close();
If you have several measures, than it will be a third dimention in query and a third cooridinate in a cellset.

Categories