Make a dynamic sqlite table creating and inserting function - c#

I have around 8-9 functions for filling tables from SQL to Sqlite and I am trying to make a dynamic function on which I will just pass some params and it will create the sqlite table (if it doesn't exist), create multiple instances in a loop of the type I want to insert in the specific table, set the properties for it and then insert it. Here are example functions:
private bool ReloadItemsFromServer()
{
try
{
using (GS.cnn)
{
SqlCommand command = new SqlCommand("rsp_FillItem_MobileDevice;", GS.cnn);
command.CommandType = System.Data.CommandType.StoredProcedure;
GS.cnn.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
string dbPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "DataBase.PremierAndroid");
using (var sqliteConn = new SQLiteConnection(dbPath))
{
sqliteConn.CreateTable<Item>();
while (reader.Read())
{
{
var newItem = new Item();
newItem.ItemID = reader.GetInt32(0);
newItem.ItemBaseID = reader.GetInt32(1);
newItem.BrandID = reader.GetInt32(2);
newItem.Issue = reader.GetInt32(3);
sqliteConn.Insert(newItem);
}
}
}
}
else
{
_dlgAlert = new AlertDialog.Builder(this).Create();
_dlgAlert.SetMessage(Resources.GetString(Resource.String.NoRowsForItemFound));
_dlgAlert.SetTitle(Resources.GetString(Resource.String.Error));
_dlgAlert.SetButton("OK", delegate { });
_dlgAlert.Show();
return false;
}
reader.Close();
}
return true;
}
catch (Exception ex)
{
_dlgAlert = new AlertDialog.Builder(this).Create();
_dlgAlert.SetMessage(ex.Message);
_dlgAlert.SetTitle(Resources.GetString(Resource.String.Error));
_dlgAlert.SetButton("OK", delegate { });
_dlgAlert.Show();
return false;
}
finally
{
if (GS.cnn.State != ConnectionState.Closed)
{
GS.cnn.Close();
}
}
}
and here's another one:
private bool ReloadContragentsFromServer()
{
try
{
using (GS.cnn)
{
SqlCommand command = new SqlCommand("rsp_FillContragent_MobileDevice;", GS.cnn);
command.CommandType = System.Data.CommandType.StoredProcedure;
GS.cnn.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
string dbPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "DataBase.PremierAndroid");
using (var sqliteConn = new SQLiteConnection(dbPath))
{
sqliteConn.CreateTable<Contragent>();
while (reader.Read())
{
{
var newContragent = new Contragent();
newContragent.ContragentID = reader.GetInt32(0);
newContragent.ContragentTypeID = reader.GetInt32(1);
newContragent.ContragentGroupID = reader.GetInt32(2);
newContragent.FullName = reader.GetString(3);
newContragent.BULSTAT = reader.GetString(4);
newContragent.ItemPriceGroupID = reader.GetInt32(5);
newContragent.ItemDiscountGroupID = reader.GetInt32(6);
sqliteConn.Insert(newContragent);
}
}
}
}
else
{
_dlgAlert = new AlertDialog.Builder(this).Create();
_dlgAlert.SetMessage(Resources.GetString(Resource.String.NoRowsForContragentFound));
_dlgAlert.SetTitle(Resources.GetString(Resource.String.Error));
_dlgAlert.SetButton("OK", delegate { });
_dlgAlert.Show();
return false;
}
reader.Close();
}
return true;
}
catch (Exception ex)
{
_dlgAlert = new AlertDialog.Builder(this).Create();
_dlgAlert.SetMessage(ex.Message);
_dlgAlert.SetTitle(Resources.GetString(Resource.String.Error));
_dlgAlert.SetButton("OK", delegate { });
_dlgAlert.Show();
return false;
}
finally
{
if (GS.cnn.State != ConnectionState.Closed)
{
GS.cnn.Close();
}
}
}
You can see what's different. How can I make it so I just call one method and give it some params so i dont have 8-9 blocks of code which are somewhat repeating?
I currently have this as a dynamic function (unfinished):
private bool LoadDataFromServer(string procedure, Type passedType)
{
try
{
using (GS.cnn)
{
SqlCommand command = new SqlCommand(procedure, GS.cnn);
command.CommandType = System.Data.CommandType.StoredProcedure;
GS.cnn.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
string dbPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "DataBase.PremierAndroid");
using (var sqliteConn = new SQLiteConnection(dbPath))
{
sqliteConn.CreateTable(passedType);
while (reader.Read()) //to do > i++ bla bla
{
{
var newItem = Activator.CreateInstance(passedType);
//newItem - loop through properties and set = reader.get(int/string)(i)
sqliteConn.Insert(newItem);
}
}
}
}
else
{
_dlgAlert = new AlertDialog.Builder(this).Create();
_dlgAlert.SetMessage(Resources.GetString(Resource.String.NoRowsForItemFound));
_dlgAlert.SetTitle(Resources.GetString(Resource.String.Error));
_dlgAlert.SetButton("OK", delegate { });
_dlgAlert.Show();
return false;
}
reader.Close();
}
return true;
}
catch (Exception ex)
{
_dlgAlert = new AlertDialog.Builder(this).Create();
_dlgAlert.SetMessage(ex.Message);
_dlgAlert.SetTitle(Resources.GetString(Resource.String.Error));
_dlgAlert.SetButton("OK", delegate { });
_dlgAlert.Show();
return false;
}
finally
{
if (GS.cnn.State != ConnectionState.Closed)
{
GS.cnn.Close();
}
}
}
Thank you

let reflection and inherit help like this:
class Caller{
// see how it sends objects to method 'processAllClasses' with different classes
void main(){
ItemClass1 i1 = new ItemClass1();
i1.setItemsB(1,2);
processAllClasses(i1);
ItemClass2 i2 = new ItemClass2();
i2.setItemsB(10, 20);
processAllClasses(i2);
}
//using reflection and inherit to process different classes, obj is what need to be processed on.
//alternative way:
//get members from the type, then assign values to them one by one
void processAllClasses(ParentClass myobjvalue)
{
Type realtype = myobjvalue.GetType();
ParentClass myobj = new ParentClass();
MethodInfo mi = realtype.GetMethod("setItemsA");
object obj = Activator.CreateInstance(realtype);
Object[] parameter = new Object[] { myobjvalue };
mi.Invoke(obj, parameter);
}
}
class ParentClass {
}
class ItemClass1: ParentClass
{
int ItemID;
int ItemBaseID;
public void setItemsA(ItemClass1 itemclass1)
{
this.ItemID = itemclass1.ItemID;
this.ItemBaseID = itemclass1.ItemBaseID;
}
public void setItemsB(int ItemID, int ItemBaseID)
{
this.ItemID = ItemID;
this.ItemBaseID = ItemBaseID;
}
}
class ItemClass2 : ParentClass
{
int ContragentID;
int ContragentTypeID;
public void setItemsA(ItemClass2 itemclass2)
{
this.ContragentID = itemclass2.ContragentID;
this.ContragentTypeID = itemclass2.ContragentTypeID;
}
public void setItemsB(int ContragentID, int ContragentTypeID)
{
this.ContragentID = ContragentID;
this.ContragentTypeID = ContragentTypeID;
}
}

Related

How To Identify button click of a node in dataTreeListView1 in C#

I have dataTreeListView named dataTreeListView1 i wish to get the name of the node which i clicked can any one please help me to do this
in the above picture if i click yes i wish to get yes on messagebox
what i tried to do is
private void dataTreeListView1_AfterSelect(object sender, EventArgs e)
{
MessageBox.Show("hello");
}
and the node are loaded dynamically means they are from database.
List<Class3> list = new List<Class3>();
list = Class3.GetList(startDate, endDate, con);
this.dataTreeListView1.ParentKeyAspectName = "ParentId";
this.dataTreeListView1.RootKeyValueString = "NUll";
BrightIdeasSoftware.OLVColumn col = new BrightIdeasSoftware.OLVColumn();
col.Width = 10;
dataTreeListView1.DataSource = list;
foreach (ColumnHeader column in this.dataTreeListView1.Columns)
{
column.Width = 140 + 140 + this.dataTreeListView1.SmallImageSize.Width;
}
this.dataTreeListView1.Columns.RemoveByKey("Id");
this.dataTreeListView1.Columns.RemoveByKey("ParentId");
this is how i show data in datatreelist view
public Class3()
{
this.xName = "";
this.xId = "";
this.xParentId = "";
this.xcredit = 0.0M;
this.xdebit = 0.0M;
this.xx = 0.0M;
this.xy = 0.0M;
}
public String Ledger
{
get { return this.xName; }
set { this.xName = value; }
}
public String Id
{
get { return this.xId; }
set { this.xId = value; }
}
public String ParentId
{
get { return this.xParentId; }
set { this.xParentId = value; }
}
public Decimal Credit
{
get { return this.xcredit; }
set { this.xcredit = value; }
}
public Decimal Debit
{
get { return this.xdebit; }
set { this.xdebit = value; }
}
public decimal x
{
get { return this.xx; }
set { this.xx = value; }
}
public decimal y
{
get { return this.xy; }
set { this.xy = value; }
}
public static List<Class3> GetList(DateTime startDate, DateTime endDate, SqlConnection con)
{
List<Class3> oList = new List<Class3>();
Buisiness b = new Buisiness();
try
{
decimal totalcredit = 0;
decimal totaldebit = 0;
con.Open();
// // Make sql readable
DataTable dt = new DataTable();
string sql = #"Select Ledger.LedId,Ledger.LedName,Ledger.MasterLedger from Ledger where Ledger.Date >= #prmStartDate and Ledger.Date <= #prmEndDate group by Ledger.MasterLedger,Ledger.LedId,Ledger.LedName";
// wrap IDisposable (SqlCommand) into using
using (SqlCommand cmd = new SqlCommand(sql, con))
{
cmd.Parameters.Add("#prmStartDate", SqlDbType.DateTime).Value = startDate;
cmd.Parameters.Add("#prmEndDate", SqlDbType.DateTime).Value = endDate;
SqlDataReader da = cmd.ExecuteReader();
while (da.Read())
{
Class3 oClass = new Class3();
oClass.Ledger = da["LedName"].ToString();
oClass.Id = da["LedId"].ToString();
oClass.ParentId = da["MasterLedger"].ToString();
Dictionary<string, decimal> d = b.findclosingbalanceofledger(da["LedId"].ToString());
/* if (da["MasterLedger"].ToString() == "NUll")
{
oClass.Debit = findsumofallchilds(da["LedId"].ToString(), con, startDate, endDate);
}
else
{*/
if (d.FirstOrDefault().Key == "debit")
{
d.FirstOrDefault().Value.ToString();
d.FirstOrDefault().Value.ToString();
totaldebit = totaldebit + d.FirstOrDefault().Value;
oClass.Debit = d.FirstOrDefault().Value;
}
else if (d.FirstOrDefault().Key == "credit")
{
d.FirstOrDefault().Value.ToString();
totalcredit = totalcredit + d.FirstOrDefault().Value;
oClass.Credit = d.FirstOrDefault().Value;
}
/* }*/
oList.Add(oClass);
}
}
con.Close();
}
catch (Exception exe)
{
MessageBox.Show(exe.Message);
}
finally
{
con.Close();
}
return oList;
}
i have changed my code this
private void dataTreeListView1_AfterSelect(object sender, EventArgs e)
{
MessageBox.Show("hello");
}
to
private void dataTreeListView1_CellClick(object sender, CellClickEventArgs e)
{
MessageBox.Show("helo");
}
but no change

Binding dropdownlist with generic list in 3-tier architecture

/*data access layer */
public DataSet getdata(string procedurename, SqlParameter[] param)
{
try
{
SqlCommand command;
command = new SqlCommand(procedurename, connection);
command.CommandType = CommandType.StoredProcedure;
SqlDataAdapter adapter = new SqlDataAdapter(command);
DataSet set = new DataSet();
if (param != null)
{
for (int i = 0; i < param.Length; i++)
{
command.Parameters.Add(param[i]);
}
}
adapter.Fill(set);
return set;
}
catch (Exception ex)
{
throw ex;
}
finally
{
closeConnection();
}
}
Middle Tier:
public class dropdownbind
{
private string _itemName;
private int _itemvalue;
public int Itemvalue
{
get { return _itemvalue; }
set { _itemvalue = value; }
}
public string ItemName
{
get { return _itemName; }
set { _itemName = value; }
}
public List<dropdownbind> getDepartment()
{
DBlist obj = new DBlist();
DataSet ds = obj.getdata("str_getdepartment",null);
List<dropdownbind> departments = new List<dropdownbind>();
foreach (DataRow orow in ds.Tables[0].Rows)
{
dropdownbind dlist = new dropdownbind();
dlist.ItemName = orow["deparment_name"].ToString();
dlist.Itemvalue = int.Parse(orow["id"].ToString());
departments.Add(dlist);
}
return departments;
}
}
UI:-
protected void BindDdlList()
{
dropdownbind dlist = new dropdownbind();
List<dropdownbind> departments = dlist.getDepartment();
ddlEmpDepatment.DataSource = departments;
ddlEmpDepatment.DataTextField = dlist.ItemName;
ddlEmpDepatment.DataValueField = dlist.Itemvalue.ToString();
ddlEmpDepatment.DataBind();
}
i am trying to bind departments to dropdownlist using 3-tier architecture.
but this code is not working, it shows middletier.dropdownbind in text field.
You need to correct the DataTextField & DataValueField properties like this:-
ddlEmpDepatment.DataValueField = "Itemvalue";
ddlEmpDepatment.DataTextField = "ItemName";
You are specifying the property name rather you need to specify the property name as string.

Select items in row on a created list

I am currently creating a list in the class ExpandWindow using a method in the class JobComponent. How would I access the JobDateTime in JobList from jobDetail and assign the value to DateTimeTextBlock?
Code below:
ExpandWindow.cs
public ExpandWindow(int jobId)
{
InitializeComponent();
List<JobComponent.JobList> jobDetail = JobComponent.SelectJobBooking(jobId);
}
JobComponent.cs
public static List<JobList> SelectJobBooking(int jobId)
{
const string query = "SELECT t1.datetime FROM booking t1 " +
"WHERE t1.id=#id";
var jobList = new List<JobList>();
using (var cmd = new MySqlCommand(query, DbObject.Connection))
{
if (DbObject.Connection.State != ConnectionState.Open)
{
DbObject.OpenConnection();
}
cmd.Parameters.AddWithValue(("#id"), jobId);
try
{
using (MySqlDataReader dataReader = cmd.ExecuteReader())
{
while (dataReader.Read())
{
var item = new JobList
{
JobDateTime = dataReader["datetime"] + ""
};
jobList.Add(item);
}
dataReader.Close();
DbObject.CloseConnection();
return jobList;
}
}
catch (Exception ex)
{
ErrorHandlingComponent.LogError(ex.ToString());
throw;
}
}
}
Not exactly sure what you trying here, but think you will get idea how to get the JobDateTime.
public ExpandWindow(int jobId)
{
InitializeComponent();
List<JobComponent.JobList> jobDetail = JobComponent.SelectJobBooking(jobId);
if(jobDetail == null) return;
var item = jobDetail.FirstOrDefault();
if(item == null) return;
yourDatetimeControl.Value = item.JobDateTime;
}

In the name the owner of a procedure must be specified - sql

I wrote C# code which returns a DataTable. All parameters i.e. Connection, sQuery have proper values.
Still I am getting an error:
In the name the owner of a procedure must be specified, this improves performance
I googled it but found nothing.
This is my code:
public static DataTable getATM(ref SqlConnection Connection)
{
DataTable dtReturn;
string sQuery = "";
try
{
sQuery = "Select ATM From ATM Where Bank=1";
using (SqlStoredProcedure sspObj = new SqlStoredProcedure(sQuery, Connection, CommandType.Text))
{
dtReturn = sspObj.ExecuteDataTable();
sspObj.Dispose();
}
}
catch (Exception xObj)
{
dtReturn = new DataTable();
}
return dtReturn;
}
SqlStoredProcedure.cs:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Xml;
using System.Diagnostics;
namespace ReflectionIT.Common.Data.SqlClient {
public class SqlStoredProcedure : IDisposable {
public static readonly TraceSource TraceSource = new TraceSource("SqlStoredProcedure");
private static int _eventId = 0;
private const string _returnValue = "ReturnValue";
private SqlCommand _command;
private bool _connectionOpened = false;
public SqlStoredProcedure(string name, SqlConnection connection, CommandType comtype)
: this(name, connection, null, comtype) {
}
public SqlStoredProcedure(string name, SqlConnection connection, SqlTransaction transaction, CommandType comtype) {
if (name.IndexOf('.') == -1) {
throw new ArithmeticException("In the name the owner of a procedure must be specified, this improves performance");
}
_command = new SqlCommand(name, connection, transaction);
_command.CommandTimeout = 0;
_command.CommandType = comtype;
AddReturnValue();
}
public void Dispose() {
if (_command != null) {
_command.Dispose();
_command = null;
}
}
virtual public string Name {
get { return _command.CommandText; }
set { _command.CommandText = value; }
}
virtual public int Timeout {
get { return _command.CommandTimeout; }
set { _command.CommandTimeout = value; }
}
virtual public SqlCommand Command {
get { return _command; }
}
virtual public SqlConnection Connection {
get { return _command.Connection; }
set { _command.Connection = value; }
}
virtual public SqlTransaction Transaction {
get { return _command.Transaction; }
set { _command.Transaction = value; }
}
virtual public SqlParameterCollection Parameters {
get { return _command.Parameters; }
}
virtual public int ReturnValue {
get { return (int)_command.Parameters[_returnValue].Value; }
}
virtual public SqlParameter AddParameter(string parameterName,
SqlDbType dbType,
int size,
ParameterDirection direction) {
SqlParameter p;
if (size > 0) {
p = new SqlParameter(parameterName, dbType, size);
} else {
// size is automacally detected using dbType
p = new SqlParameter(parameterName, dbType);
}
p.Direction = direction;
Parameters.Add(p);
return p;
}
virtual public SqlParameter AddParameterWithValue(string parameterName,
SqlDbType dbType,
int size,
ParameterDirection direction,
object value) {
SqlParameter p = this.AddParameter(parameterName, dbType, size, direction);
if (value == null) {
value = DBNull.Value;
}
p.Value = value;
return p;
}
virtual public SqlParameter AddParameterWithStringValue(string parameterName,
SqlDbType dbType,
int size,
ParameterDirection direction,
string value,
bool emptyIsDBNull) {
SqlParameter p = this.AddParameter(parameterName, dbType, size, direction);
if (value == null) {
p.Value = DBNull.Value;
} else {
value = value.TrimEnd(' ');
if (emptyIsDBNull && value.Length == 0) {
p.Value = DBNull.Value;
} else {
p.Value = value;
}
}
return p;
}
virtual protected SqlParameter AddReturnValue() {
SqlParameter p = Parameters.Add(
new SqlParameter(_returnValue,
SqlDbType.Int,
/* int size */ 4,
ParameterDirection.ReturnValue,
/* bool isNullable */ false,
/* byte precision */ 0,
/* byte scale */ 0,
/* string srcColumn */ string.Empty,
DataRowVersion.Default,
/* value */ null));
return p;
}
virtual public int ExecuteNonQuery() {
int rowsAffected = -1;
try {
Prepare("ExecuteNonQuery");
rowsAffected = _command.ExecuteNonQuery();
TraceResult("RowsAffected = " + rowsAffected.ToString());
} catch (SqlException e) {
throw TranslateException(e);
} finally {
CloseOpenedConnection();
}
return rowsAffected;
}
virtual public SqlDataReader ExecuteReader() {
SqlDataReader reader;
try {
Prepare("ExecuteReader");
reader = _command.ExecuteReader();
TraceResult(null);
} catch (SqlException e) {
throw TranslateException(e);
} finally {
CloseOpenedConnection();
}
return reader;
}
virtual public SqlDataReader ExecuteReader(CommandBehavior behavior) {
SqlDataReader reader;
try {
Prepare("ExecuteReader");
reader = _command.ExecuteReader(behavior);
TraceResult(null);
} catch (SqlException e) {
throw TranslateException(e);
} finally {
CloseOpenedConnection();
}
return reader;
}
virtual public object ExecuteScalar() {
object val = null;
try {
Prepare("ExecuteScalar");
val = _command.ExecuteScalar();
TraceResult("Scalar Value = " + Convert.ToString(val));
} catch (SqlException e) {
throw TranslateException(e);
} finally {
CloseOpenedConnection();
}
return val;
}
virtual public XmlReader ExecuteXmlReader() {
XmlReader reader;
try {
Prepare("ExecuteXmlReader");
reader = _command.ExecuteXmlReader();
TraceResult(null);
} catch (SqlException e) {
throw TranslateException(e);
} finally {
CloseOpenedConnection();
}
return reader;
}
virtual public DataSet ExecuteDataSet() {
DataSet dataset = new DataSet();
this.ExecuteDataSet(dataset);
return dataset;
}
virtual public DataSet ExecuteDataSet(DataSet dataSet) {
try {
Prepare("ExecuteDataSet");
SqlDataAdapter a = new SqlDataAdapter(this.Command);
a.Fill(dataSet);
TraceResult("# Tables in DataSet = " + dataSet.Tables.Count);
} catch (SqlException e) {
throw TranslateException(e);
} finally {
CloseOpenedConnection();
}
return dataSet;
}
virtual public DataTable ExecuteDataTable() {
DataTable dt = null;
try {
Prepare("ExecuteDataTable");
SqlDataAdapter a = new SqlDataAdapter(this.Command);
dt = new DataTable();
a.Fill(dt);
TraceResult("# Rows in DataTable = " + dt.Rows.Count);
} catch (SqlException e) {
throw TranslateException(e);
} finally {
CloseOpenedConnection();
}
return dt;
}
protected Exception TranslateException(SqlException ex) {
Exception dalException = null;
SqlStoredProcedure.TraceSource.TraceEvent(TraceEventType.Error, _eventId, "{0} throwed exception: {1}", this.Name, ex.ToString());
foreach (SqlError error in ex.Errors) {
if (error.Number >= 50000) {
dalException = new DalException(error.Message, ex);
}
}
if (dalException == null) {
switch (ex.Number) {
case 17:
case 4060:
case 18456:
dalException = new DalLoginException(ex.Message, ex);
break;
case 547:
dalException = new DalForeignKeyException(ex.Message, ex);
break;
case 1205:
dalException = new DalDeadLockException(ex.Message, ex);
break;
case 2627:
case 2601:
dalException = new DalUniqueConstraintException(ex.Message, ex);
break;
default:
dalException = new DalException(ex.Message, ex);
break;
}
}
return dalException;
}
protected void Prepare(string executeType) {
_eventId++;
if (_eventId > ushort.MaxValue) {
_eventId = 0;
}
SqlStoredProcedure.TraceSource.TraceEvent(TraceEventType.Information, _eventId, "{0}: {1}", executeType, this.Name);
TraceParameters(true);
if (_command.Connection.State != ConnectionState.Open) {
_command.Connection.Open();
_connectionOpened = true;
}
}
private void TraceParameters(bool input) {
if (SqlStoredProcedure.TraceSource.Switch.ShouldTrace(TraceEventType.Verbose) && this.Parameters.Count > 0) {
foreach (SqlParameter p in this.Parameters) {
bool isInput = p.Direction != ParameterDirection.ReturnValue && p.Direction != ParameterDirection.Output;
bool isOutput = p.Direction != ParameterDirection.Input;
if ((input && isInput) || (!input && isOutput)) {
SqlStoredProcedure.TraceSource.TraceEvent(TraceEventType.Verbose, _eventId, "SqlParamter: Name = {0}, Value = '{1}', Type = {2}, Size = {3}", p.ParameterName, p.Value, p.DbType, p.Size);
}
}
}
}
protected void CloseOpenedConnection() {
if ((_command.Connection.State == ConnectionState.Open) & _connectionOpened)
_command.Connection.Close();
}
protected void TraceResult(string result) {
if (result != null) {
SqlStoredProcedure.TraceSource.TraceEvent(TraceEventType.Verbose, _eventId, "Result: {0}", result);
}
TraceParameters(false);
}
}
}
SqlStoredProcedure() is checking that there is a dot in your stored procedure name and if there isn't throwing that exception, so prefix your stored procedure name with "dbo." or whatever it is e.g.:
dbo.myProcedureName
It improves performance in the sense that SQL doesn't have to search all the users to find the proc first.

Using Dapper with Oracle stored procedures which return cursors

How would one go about using Dapper with Oracle stored procedures which return cursors?
var p = new DynamicParameters();
p.Add("foo", "bar");
p.Add("baz_cursor", dbType: DbType.? , direction: ParameterDirection.Output);
Here, the DbType is System.Data.DbType which does not have a Cursor member. I've tried using DbType.Object but that does not work with both OracleClient and OracleDataAcess.
What would be a possible way to use OracleType or OracleDbType instead?
Thanks for the solution here. I achieved the same thing with a little less code using a simple DynamicParameter decorator:
public class OracleDynamicParameters : SqlMapper.IDynamicParameters
{
private readonly DynamicParameters dynamicParameters = new DynamicParameters();
private readonly List<OracleParameter> oracleParameters = new List<OracleParameter>();
public void Add(string name, object value = null, DbType? dbType = null, ParameterDirection? direction = null, int? size = null)
{
dynamicParameters.Add(name, value, dbType, direction, size);
}
public void Add(string name, OracleDbType oracleDbType, ParameterDirection direction)
{
var oracleParameter = new OracleParameter(name, oracleDbType, direction);
oracleParameters.Add(oracleParameter);
}
public void AddParameters(IDbCommand command, SqlMapper.Identity identity)
{
((SqlMapper.IDynamicParameters)dynamicParameters).AddParameters(command, identity);
var oracleCommand = command as OracleCommand;
if (oracleCommand != null)
{
oracleCommand.Parameters.AddRange(oracleParameters.ToArray());
}
}
}
You would have to implement:
public interface IDynamicParameters
{
void AddParameters(IDbCommand command, Identity identity);
}
Then in the AddParameters callback you would cast the IDbCommand to an OracleCommand and add the DB specific params.
Add this class to your project
and your code should like below :-
var p = new OracleDynamicParameters();
p.Add("param1", pAuditType);
p.Add("param2", pCommnId);
p.Add("outCursor", dbType: OracleDbType.RefCursor, direction: ParameterDirection.Output);
using (var multi = cnn.QueryMultiple("procedure_name", param: p, commandType: CommandType.StoredProcedure))
{
var data = multi.Read();
return data;
}
Just to elaborate on Sams suggestion here's what I came up with. Note that this code is brittle and is now just for Oracle.
Modified Dapper 1.7
void SqlMapper.IDynamicParameters.AddParameters(IDbCommand command, SqlMapper.Identity identity)
{
if (templates != null)
{
foreach (var template in templates)
{
var newIdent = identity.ForDynamicParameters(template.GetType());
Action<IDbCommand, object> appender;
lock (paramReaderCache)
{
if (!paramReaderCache.TryGetValue(newIdent, out appender))
{
appender = SqlMapper.CreateParamInfoGenerator(newIdent);
paramReaderCache[newIdent] = appender;
}
}
appender(command, template);
}
}
foreach (var param in parameters.Values)
{
string name = Clean(param.Name);
bool add = !((Oracle.DataAccess.Client.OracleCommand)command).Parameters.Contains(name);
Oracle.DataAccess.Client.OracleParameter p;
if(add)
{
p = ((Oracle.DataAccess.Client.OracleCommand)command).CreateParameter();
p.ParameterName = name;
} else
{
p = ((Oracle.DataAccess.Client.OracleCommand)command).Parameters[name];
}
var val = param.Value;
p.Value = val ?? DBNull.Value;
p.Direction = param.ParameterDirection;
var s = val as string;
if (s != null)
{
if (s.Length <= 4000)
{
p.Size = 4000;
}
}
if (param.Size != null)
{
p.Size = param.Size.Value;
}
if (param.DbType != null)
{
p.DbType = param.DbType.Value;
}
if (add)
{
if (param.DbType != null && param.DbType == DbType.Object)
{
p.OracleDbType = Oracle.DataAccess.Client.OracleDbType.RefCursor;
((Oracle.DataAccess.Client.OracleCommand)command).Parameters.Add(p);
}
else
{
((Oracle.DataAccess.Client.OracleCommand)command).Parameters.Add(p);
}
}
param.AttachedParam = p;
}
}
Test code
class Program
{
static void Main(string[] args)
{
OracleConnection conn = null;
try
{
const string connString = "DATA SOURCE=XE;PERSIST SECURITY INFO=True;USER ID=HR;PASSWORD=Adv41722";
conn = new OracleConnection(connString);
conn.Open();
var p = new DynamicParameters();
p.Add(":dep_id", 60);
p.Add(":employees_c", dbType: DbType.Object, direction: ParameterDirection.Output);
p.Add(":departments_c", dbType: DbType.Object, direction: ParameterDirection.Output);
// This will return an IEnumerable<Employee> // How do I return both result?
var results = conn.Query<Employee>("HR_DATA.GETCURSORS", p, commandType: CommandType.StoredProcedure);
}
catch (Exception exception)
{
Console.WriteLine(exception);
throw;
}
finally
{
if (conn != null && conn.State == ConnectionState.Open)
{
conn.Close();
}
}
Console.WriteLine("Fininhed!");
Console.ReadLine();
}
}
class Employee
{
public int Employee_ID { get; set; }
public string FIRST_NAME { get; set; }
public string LAST_NAME { get; set; }
public string EMAIL { get; set; }
public string PHONE_NUMBER { get; set; }
}

Categories