This bit of code runs on Windows Compact Framework and what it does is obvious. It looks as it should be refactored (especially considering that I may want to add cmd.ExecuteResultSet() later), but I can't see an elegant way to do it. Any ideas appreciated.
internal void RunNonQuery(string query)
{
string connString = GetLocalConnectionString();
using (SqlCeConnection cn = new SqlCeConnection(connString))
{
cn.Open();
SqlCeCommand cmd = cn.CreateCommand();
cmd.CommandText = query;
cmd.ExecuteNonQuery();
}
}
internal int RunScalar(string query)
{
string connString = GetLocalConnectionString();
using (SqlCeConnection cn = new SqlCeConnection(connString))
{
cn.Open();
SqlCeCommand cmd = cn.CreateCommand();
cmd.CommandText = query;
return int.Parse(cmd.ExecuteScalar().ToString());
}
}
I'm not sure I would refactor it, but perhaps:
static void PerformQuery(string connectionString, string command,
Action<SqlCeCommand> action)
{ //TODO: sanity checks...
using(SqlCeConnection conn = new SqlCeConnection(connectionString))
using(SqlCeCommand cmd = conn.CreateCommand()) {
cmd.CommandText = command;
conn.Open();
action(cmd);
}
}
internal void RunNonQuery(string query)
{
string connString = GetLocalConnectionString();
PerformQuery(connString, query, cmd => cmd.ExecuteNonQuery());
}
internal int RunScalar(string query)
{
int result = 0;
string connString = GetLocalConnectionString();
PerformQuery(connString, query,
cmd => {result = int.Parse(cmd.ExecuteScalar().ToString()); }
);
return result;
}
Otherwise - just maybe a CreateAndOpenConnection(string) method, and a CreateCommand(SqlCeConnection,string) method.
If you are using C# 3.0, you could do something like the following:
private T CreateCommand<T>(string query, Func<SqlCeCommand, T> func)
{
var connString = GetLocalConnectionString();
using (var cn = new SqlCeConnection(connString))
{
cn.Open();
using (var cmd = cn.CreateCommand())
{
cmd.CommandText = query;
return func(cmd);
}
}
}
private void CreateCommand(string query, Action<SqlCeCommand> action)
{
CreateCommand<object>(query, cmd =>
{
action(cmd);
return null;
});
}
internal void RunNonQuery(string query)
{
CreateCommand(query, cmd => cmd.ExecuteNonQuery());
}
internal int RunScalar(string query)
{
return CreateCommand(query, cmd =>
int.Parse(cmd.ExecuteScalar().ToString()));
}
I would create a class out of the code to wrap the connection creation and command execution logic. This will provide you with a single place to implement transactions in the future and will consolidate creation of the connection and command. This consolidation will allow for settings timeouts, joining transactions, etc.
class Connection : IDisposable
{
readonly SqlConnection _conn;
public Connection()
{
string connString = GetLocalConnectionString();
_conn = new SqlConnection(connString);
_conn.Open();
}
public void Dispose() { _conn.Dispose(); }
public SqlCommand CreateCommand(string qry)
{
SqlCommand cmd = _conn.CreateCommand();
cmd.CommandText = qry;
//cmd.CommandTimeout = TimeSpan.FromMinutes(x);
return cmd;
}
public int ExecuteNonQuery(string qry)
{
using (SqlCommand cmd = CreateCommand(qry))
return cmd.ExecuteNonQuery();
}
public int RunScalar(string qry)
{
using (SqlCommand cmd = CreateCommand(qry))
return int.Parse(cmd.ExecuteScalar().ToString());
}
}
Then if you still want to maintain your original API, you do the following:
class SqlCode
{
internal void RunNonQuery(string query)
{
using (Connection cn = new Connection())
cn.ExecuteNonQuery(query);
}
internal int RunScalar(string query)
{
using (Connection cn = new Connection())
return cn.RunScalar(query);
}
}
The only thing left is to re-insert the 'Ce' in the SqlXxxx stuff ;)
Related
I have a DataAccessBase class with the following 2 data access methods. One for ExecuteScalar and one for ExecuteNonQuery. Is it possible to consolidate it into one generic method or is even worth worrying about?
protected static int ExecuteNonQuery(SqlCommand command)
{
using (SqlConnection connection = new SqlConnection(_connStr))
{
command.Connection = connection;
SqlDataAdapter da = new SqlDataAdapter(command);
command.Connection.Open();
int result = command.ExecuteNonQuery();
return result;
}
}
protected static string ExecuteScalar(SqlCommand command)
{
using (SqlConnection connection = new SqlConnection(_connStr))
{
command.Connection = connection;
SqlDataAdapter da = new SqlDataAdapter(command);
command.Connection.Open();
string result = command.ExecuteScalar().ToString();
return result;
}
}
private static DataTable GetDT(int id)
{
using (SqlConnection connection = new SqlConnection(_connStr))
{
string query = "select id, userid, name from tasks where id = #id";
SqlCommand command = new SqlCommand(query, connection);
SqlDataAdapter da = new SqlDataAdapter(command);
//Parameterized query to prevent injection attacks
command.Parameters.AddWithValue("id", id);
DataTable dt = new DataTable();
da.Fill(dt);
return dt;
}
}
You can definitely avoid the current repetition you've got with a generic method, but I wouldn't try to reduce it to a single method. Here's what I'd potentially do:
protected static int ExecuteNonQuery(SqlCommand command) =>
ExecuteCommand(command, cmd => cmd.ExecuteNonQuery());
protected static string ExecuteScalar(SqlCommand command) =>
ExecuteCommand(command, cmd => cmd.ExecuteScalar().ToString());
private static T ExecuteCommand<T>(SqlCommand command, Func<SqlCommand, T> resultRetriever)
{
using (SqlConnection connection = new SqlConnection(_connStr))
{
command.Connection = connection;
command.Connection.Open();
return resultRetriver(command);
}
}
For the DataTable one, following the same pattern you'd create the command first:
protected static DataTable GetDataTable(SqlCommand command) =>
ExecuteCommand(cmd =>
{
SqlDataAdapter da = new SqlDataAdapter(cmd)
DataTable table = new DataTable();
da.FillTable(table);
return table;
});
You can convert the ExecuteScalar to a generic method, allowing you to change the return type.
public T ExecuteScalar<T>(SqlCommand command)
{
using (SqlConnection connection = new SqlConnection(_connStr))
{
command.Connection = connection;
//SqlDataAdapter da = new SqlDataAdapter(command); //not needed...
command.Connection.Open();
var result = command.ExecuteScalar();
//rather than just returning result with an implicit cast, use Max's trick from here: https://stackoverflow.com/a/2976427/361842
if (Convert.IsDbNull(result))
return default(T); //handle the scenario where the returned value is null, but the type is not nullable (or remove this to have such scenarios throw an exception)
if (result is T)
return (T)result;
else
(T)Convert.ChangeType(result, typeof(T));
}
}
The logic is different in this method to in the ExecuteNonQuery function though, so you cannot have both represented by the same method.
Update
Regarding your question about the data table, I've taken and adapted #JonSkeet's answer to allow the class to also handle data tables:
public class SqlDatabaseThing //: ISqlDatabaseThing
{
// ... additional code here ... //
public int ExecuteNonQuery(SqlCommand command, IEnumerable<SqlParameter> sqlParameters = new[]{}) =>
ExecuteNonQuery(_connStr, command, sqlParameters);
public static int ExecuteNonQuery(string connectionString, SqlCommand command, IEnumerable<SqlParameter> sqlParameters = new[]{}) =>
ExecuteCommand(connectionString, command, cmd => cmd.ExecuteNonQuery());
public T ExecuteScalar(SqlCommand command, IEnumerable<SqlParameter> sqlParameters = new[]{}) =>
ExecuteScalar(_connStr, command, sqlParameters);
public static T ExecuteScalar(string connectionString, SqlCommand command, IEnumerable<SqlParameter> sqlParameters = new[]{}) =>
ExecuteCommand(connectionString, command, cmd => ConvertSqlCommandResult(cmd.ExecuteScalar()));
public DataTable ExecuteToDataTable(SqlCommand command, IEnumerable<SqlParameter> sqlParameters = new[]{}) =>
ExecuteToDataTable(_connStr, command, sqlParameters);
public static DataTable ExecuteToDataTable(string connectionString, SqlCommand command, IEnumerable<SqlParameter> sqlParameters = new[]{}) =>
ExecuteCommand(connectionString, command, cmd => PopulateDataTable(cmd));
private static T ExecuteCommand<T>(string connectionString, SqlCommand command, IEnumerable<SqlParameter> sqlParameters, Func<SqlCommand, T> resultRetriever)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
command.Parameters.AddRange(sqlParameters);
command.Connection = connection;
command.Connection.Open();
return resultRetriver(command);
}
}
private static DataTable PopulateDataTable(SqlCommand command)
{
var da = SqlDataAdapter(command);
var dt = new DataTable();
da.Fill(dt);
return dt;
}
private static T ConvertSqlCommandResult(object result)
{
if (Convert.IsDbNull(result))
return default(T);
if (result is T)
return result as T;
(T)Convert.ChangeType(result, typeof(T));
}
}
NB: In your code you'd included logic related to getting specific tasks. That should be kept separate from your generic database logic (i.e. as presumably you'll want to return data tables for various queries, and don't want to have to rewrite your GetDT code each time). As such I've provided additional sample code below showing how you could separate that logic into another class...
public class TaskRepository //: IRepository<Task>
{
ISqlDatabaseThing db;
public TaskRepository(ISqlDatabaseThing db)
{
this.db = db;
}
readonly string GetByIdCommand = "select id, userid, name from tasks where id = #id";
readonly string GetByIdCommandParameterId = "#id"
readonly SqlDbType GetByIdCommandParameterIdType = SqlDbType.BigInt;
public Task GetById(long id)
{
var command = new SqlCommand(GetByIdCommand);
var parameters = IEnumerableHelper.ToEnumerable<SqlParameter>(new SqlParameter(GetByIdCommandIdParameter, GetByIdCommandIdParameterType, id));
var dataTable = db.ExecuteToDataTable(command, parameters);
return DataTableToTask(dataTable)[0];
}
private IEnumerable<Task> DataTableToTask(DataTable dt)
{
foreach (var row in dt.Rows)
{
yield return DataRowToTask(row);
}
}
private Task DataRowToTask (DataRow dr)
{
return new Task()
{
Id = dr["Id"]
,Name = dr["Name"]
,UserId = dr["UserId"]
};
}
}
public static class IEnumerableHelper
{
public static IEnumerable<T> ToEnumerable<T>(params T[] parameters)
{
return parameters;
}
}
NB: This code is untested; any issues please let me know.
Why am I getting this error:
Connection state has not been intialized
when I'm using one method in other?
This is my DbConnectio.cs:
public class DbContext
{
public SqlConnection sqlconn = null;
public SqlConnection DbConnection
{
get { return sqlconn; }
set { value = sqlconn; }
}
public DbContext()
{
string cs = ConfigurationManager.ConnectionStrings["CTXDB"].ConnectionString;
sqlconn = new SqlConnection(cs);
}
}
web.config:
<add name="CTXDB"
connectionString="Data Source=Md;Initial Catalog=Md;User ID=sa;Password=123;MultipleActiveResultSets=true"
providerName="System.Data.SqlClient" />
This is my Repo.cs - here I'm implementing my business logic:
DbContext db = new DbContext();
public Employee FindEmpById(int key)
{
SqlConnection conn = db.DbConnection;
try
{
var employee = new Employee();
if (conn.State != System.Data.ConnectionState.Open)
{
conn.Open();
}
SqlCommand cmd = new SqlCommand("Sp_GetEmployeeById", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#EmpId", key);
SqlDataReader rdr = cmd.ExecuteReader();
if (rdr.HasRows == true)
{
while (rdr.Read())
{
employee.Emp_Id = Convert.ToInt32(rdr["Emp_Id"]);
employee.EmpName = rdr["EmpName"].ToString();
employee.Email = rdr["Email"].ToString();
employee.Psw = rdr["Psw"].ToString();
}
}
return employee;
}
catch (Exception)
{
throw;
}
finally
{
if (conn != null)
{
if (conn.State == ConnectionState.Open)
conn.Close();
conn.Dispose();
}
}
}
This FindEmpById I call in DeleteEmpById function
public void DeleteEmpById(int Key)
{
SqlConnection Con = db.DbConnection;
var x = FindEmpById(Key);
if (x != null)
{
if (Con.State != ConnectionState.Open)
{
Con.Open();
}
SqlCommand cmd = new SqlCommand("sp_DeleteById", Con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#EmpId", Key);
cmd.ExecuteNonQuery();
}
}
FindEmpById disposes the connection conn.Dispose();. So, when you try to use it afterwards, it is not valid any more.
Don't try to reuse a connection. Create a new connection each time you need one. Internally the physical connections are pooled automatically, i.e., the same physical connection will be reused when possible. Creating a new connection with new SqlConnection is lightweight.
Instead of doing
SqlConnection conn = db.DbConnection; // WRONG!
// All your try catch finally and testing for conn.State --- WRONG!
do
// OK!
using (SqlConnection conn = db.CreateConnection()) {
conn.Open();
...
} // Automatically closed and disposed here.
Where CreateConnection creates a new SqlConnection at each call. This is also much easier and straight forward. Change your DbContext class to
public class DbContext
{
private static readonly string _connectionString;
static DbContext()
{
_connectionString = ConfigurationManager.ConnectionStrings["CTXDB"].ConnectionString;
}
public SqlConnection CreateConnection()
{
return new SqlConnection(_connectionString);
}
}
Your overhauled FindEmpById method becomes
public Employee FindEmpById(int key)
{
using (SqlConnection conn = db.CreateConnection())
using (SqlCommand cmd = new SqlCommand("Sp_GetEmployeeById", conn)) {
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#EmpId", key);
var employee = new Employee();
conn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader()) {
if (rdr.Read()) {
employee.Emp_Id = Convert.ToInt32(rdr["Emp_Id"]);
employee.EmpName = rdr["EmpName"].ToString();
employee.Email = rdr["Email"].ToString();
employee.Psw = rdr["Psw"].ToString();
}
}
return employee;
}
}
Btw: You don't need to call FindEmpById(Key) before deleting. Just delete. It is not an error to delete 0 records in SQL.
public void DeleteEmpById(int Key)
{
using (SqlConnection conn = db.CreateConnection())
using (SqlCommand cmd = new SqlCommand("sp_DeleteById", conn)) {
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#EmpId", Key);
conn.Open();
cmd.ExecuteNonQuery();
}
}
I have a Class that processes DB column metadata. One of the Properties of the Class is the table in question. This is passed to the object via the constructor. Also in the constructor I apply some logic to assign other variables within the class. To do this there are a number of private methods that connect to a DB, query something about the table, and return a value to the variable.
My problem is that I have a lot of different methods doing pretty much the same thing, but returning a different datatype. So for example my code is something like this
public Column(string tableName)
{
strTableName = tableName;
pkColumnName = GetPKColumnName(tableName);
pkColumnLenght = GetPKColumnLenght(tableName);
}
private string GetPKColumnName(string tableName)
{
string query = String.Format("SELECT myColName FROM myTable where myTableName = {0}", tableName);
string result = "";
try
{
using(SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["MyDB"].ConnectionString))
{
con.Open();
using (SqlCommand command = new SqlCommand(query, con))
{
result = (string)command.ExecuteScalar();
}
}
}
catch (SqlException ex)
{
Console.WriteLine(ex.Message);
}
return result;
}
private int GetPKColumnLenght(string tableName)
{
string query = String.Format("SELECT myColLenght FROM myTable where myTableName = {0}", tableName);
int result = 0;
try
{
using(SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["MyDB"].ConnectionString))
{
con.Open();
using (SqlCommand command = new SqlCommand(query, con))
{
result = (int)command.ExecuteScalar();
}
}
}
catch (SqlException ex)
{
Console.WriteLine(ex.Message);
}
return result;
}
There are many other methods like this also. This didn't look great to me, so I was wondering what the best practice was for something like this.
Should I just declare the return type as an object and do the datatype conversions when assigning the returned value to my variable?
My answer and the other assume different questions. It appears to me that you are trying to query a single value from a specific column and that you have to create a new method because the types are different. That said, I would personally just use a simple ORM solution and the other answer certainly is not wrong, just another abstraction.
You will want to use generics and cast to the generic.
I haven't tested this code, it is more of a guideline.
private T GetValue<T>(string tableName, colName)
{
string query = String.Format("SELECT {0} FROM myTable where myTableName = {1}", colName, tableName);
T result = default(T);
try
{
using(SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["MyDB"].ConnectionString))
{
con.Open();
using (SqlCommand command = new SqlCommand(query, con))
{
result = (T)command.ExecuteScalar();
}
}
}
catch (SqlException ex)
{
Console.WriteLine(ex.Message);
}
return result;
}
Create SqlManager class
public class SqlManager
{
public static string ConnectionString
{
get
{
return "Your ConnectionString"
}
}
public static SqlConnection GetSqlConnection(SqlCommand cmd)
{
if (cmd.Connection == null)
{
SqlConnection conn = new SqlConnection(ConnectionString);
conn.Open();
cmd.Connection = conn;
return conn;
}
return cmd.Connection;
}
public static object ExecuteScalar(SqlCommand cmd)
{
SqlConnection conn = GetSqlConnection(cmd);
try
{
return cmd.ExecuteScalar();
}
catch
{
throw;
}
finally
{
conn.Close();
}
}
}
Now your methods, for the second one same thing:
private string GetPKColumnName(string tableName)
{
string query = String.Format("", tableName);
SqlCommand cmd = new SqlCommand();
cmd.CommandText = #"SELECT myColName FROM myTable where myTableName = #TableName";
cmd.Parameters.AddWithValue("#TableName", tableName);
object result = SqlManager.ExecuteScalar(cmd);
return result != null ? (int)object: 0;
}
There is a console app where I have a sql select statement with some inner joins.I want for every result of this statement to update a column of one of these tables with a new value using C#.
Here what I've already tried:
using System;
using System.Data.SqlClient;
using System.Configuration;
using System.Data;
namespace MyProgram
{
class Program
{
private static SqlConnection _connection;
private static SqlTransaction _transaction;
static void Main(string[] args)
{
using (var connection = new SqlConnection())
{
try
{
connection.ConnectionString = ConfigurationManager.ConnectionStrings["myConfig"].ConnectionString;
connection.Open();
_connection = connection;
using (var command = connection.CreateCommand())
{
command.CommandText =
"My Select sql stament with inner joins";
using (var reader = command.ExecuteReader())
{
var indexOfColumn3 = reader.GetOrdinal("IDExtObject");
while (reader.Read())
{
_transaction = _connection.BeginTransaction("UpdateTransaction");
command.Transaction = _transaction;
var extId = reader.GetValue(indexOfColumn3).ToString();
string finalId = "Something new...";
try
{
UpdateIdSqlTransaction(extId, finalId);
_transaction.Commit();
}
catch (Exception)
{
_transaction.Rollback();
}
}
}
}
}
catch (Exception)
{
if (_transaction != null)
_transaction.Rollback();
}
finally
{
if (connection.State == ConnectionState.Open)
{
connection.Close();
}
}
}
Console.ReadLine();
}
private static void UpdateIdSqlTransaction(string objectId, string newId)
{
using (_connection)
{
SqlCommand command = _connection.CreateCommand();
command.Connection = _connection;
var commandText = "The update SQL statement...";
command.CommandText = commandText;
command.Parameters.AddWithValue("#ID", objectId);
command.Parameters.AddWithValue("#newId", newId);
command.ExecuteNonQuery();
}
}
}
}
The problem is that I am getting this exception:
{"New transaction is not allowed because there are other threads running in the session."}
What is the problem and how can I achieve this?
You need to close the existing connection that you are using to Read the data. DataReader is a read only stream of data.
Do it as given below:
First read the data and store it in a variable. Close the connection that DataReader is using to read the data.
Now use the loop and create a transaction to update the data using the same transaction.
Once updated, you can commit the transaction.
Change your code as per the instructions given. Thanks
Check this link for more details on SO
Try the following code. Note that I have not run it as I do not have database set up for the code. Hope it helps.
using System;
using System.Data.SqlClient;
using System.Configuration;
using System.Data;
using System.Collections.Generic;
namespace MyProgram
{
class Item
{
public string OldValue { get; set; }
public string NewValue { get; set; }
}
class Program
{
//private static SqlConnection _connection;
private static string connectionString = ConfigurationManager.ConnectionStrings["myConfig"].ConnectionString;
static void Main(string[] args)
{
List<Item> items = new List<Item>();
ReadData(ref items);
UpdateIdSqlTransaction(items);
Console.ReadLine();
}
private static void ReadData(ref List<Item> items)
{
using (var connection = new SqlConnection())
{
connection.ConnectionString = connectionString;
connection.Open();
//_connection = connection;
using (var command = connection.CreateCommand())
{
command.CommandText =
"My Select sql stament with inner joins";
using (var reader = command.ExecuteReader())
{
var indexOfColumn3 = reader.GetOrdinal("IDExtObject");
while (reader.Read())
{
var extId = reader.GetValue(indexOfColumn3).ToString();
string finalId = "Something new...";
items.Add(new Item() { OldValue = extId, NewValue = finalId });
}
}
}
}
}
private static void UpdateIdSqlTransaction(List<Item> items)
{
SqlTransaction transaction;
using (var connection = new SqlConnection())
{
connection.ConnectionString = connectionString;
connection.Open();
using (SqlCommand command = connection.CreateCommand())
{
command.Connection = connection;
transaction = connection.BeginTransaction("UpdateTransaction");
command.Transaction = transaction;
try
{
foreach (var item in items)
{
var commandText = "The update SQL statement...";
command.CommandText = commandText;
command.Parameters.AddWithValue("#ID", item.OldValue);
command.Parameters.AddWithValue("#newId", item.NewValue);
command.ExecuteNonQuery();
}
transaction.Commit();
}
catch (Exception)
{
transaction.Rollback();
//Log the exception here. To know, why this failed.
}
}
}
}
}
}
The issue here is you are trying to read and update at the same time. Within the datareader you are calling update function which is not allowed to maintain the DB in a consistent state.
Here is a bit modified code, where arraylist is used to store data from reader and then loop through to call update function.
class Program
{
private static SqlConnection _connection;
private static SqlTransaction _transaction;
private static ArrayList array;
static void Main(string[] args)
{
_connection = new SqlConnection(ConfigurationManager.ConnectionStrings["myConfig"].ConnectionString);
try
{
using (_connection)
{
string finalId = "Something new...";
var command = _connection.CreateCommand();
command.CommandText = "your query";
_connection.Open();
array = new ArrayList();
using (var reader = command.ExecuteReader())
{
var indexOfColumn3 = reader.GetOrdinal("IDExtObject");
while (reader.Read())
{
var extId = reader.GetValue(indexOfColumn3).ToString();
array.Add(extId);
}
}
foreach (string id in array)
{
UpdateIdSqlTransaction(id, finalId);
}
}
}
catch (Exception)
{
}
finally
{
if (_connection.State == ConnectionState.Open)
{
_connection.Close();
}
}
Console.ReadLine();
}
private static void UpdateIdSqlTransaction(string objectId, string newId)
{
try
{
if (_connection.State == ConnectionState.Closed)
{
_connection.Open();
}
SqlCommand command = _connection.CreateCommand();
command.Connection = _connection;
_transaction = _connection.BeginTransaction("UpdateTransaction");
command.Transaction = _transaction;
var commandText = "your update statement";
command.CommandText = commandText;
command.Parameters.AddWithValue("#ID", objectId);
command.Parameters.AddWithValue("#newId", newId);
command.ExecuteNonQuery();
_transaction.Commit();
}
catch (Exception)
{
_transaction.Rollback();
}
finally
{
if (_connection.State == ConnectionState.Open)
{
_connection.Close();
}
}
}
}
I am trying to write c# function to read some data from oracle table
My functions:
public static writeConsole(string query, string connectionString, string driver)
{
//driver = Oracle.ManagedDataAccess.Client
using (var conn = DbProviderFactories.GetFactory(driver).CreateConnection())
{
using (var cmd = conn.CreateCommand())
{
cmd.Connection.ConnectionString = connectionString;
cmd.CommandType = CommandType.Text;
cmd.CommandText = query;
foreach (var item in ReadDouble(cmd))
{
Console.WriteLine(item);
}
}
}
}
private static IEnumerable<double> ReadDouble(IDbCommand cmd)
{
using (var r = cmd.ExecuteReader())
{
while (r.Read())
yield return r.GetDouble(0);
}
}
There is no problem in connection, nor executing query.
When I read data from oracle table in type number(9) it returns proper values I am expecting.
When I read data from table, where type is number(9,2) it returns empty value (like empty table).
Notice: This is only sample of the code. It has to be written using IDb interfaces
Thank you for help
Possibly it is problem with type mapping. Try this:
http://docs.oracle.com/html/E10927_01/featSafeType.htm#i1008428
And this:
https://community.oracle.com/message/3582080
public static writeConsole(string query, string connectionString, string driver)
{
//driver = Oracle.ManagedDataAccess.Client
using (var conn = DbProviderFactories.GetFactory(driver).CreateConnection())
{
using (var cmd = conn.CreateCommand())
{
cmd.Connection.ConnectionString = connectionString;
cmd.CommandType = CommandType.Text;
cmd.CommandText = query;
var reader = cmd.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(reader[0]+"");
}
}
}
}
You can Try
OracleConnection conn = new OracleConnection(connectionString);
OracleCommand cmd = new OracleCommand(query, conn);
if (conn.State == ConnectionState.Closed)
conn.Open();
OracleDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(reader[0]+"");
}