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
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());
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
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
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));
}
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.