How to design Database Access Layer to contain Sql libraries in one place - data-access-layer

I have a handler class for every table and I am doing all the DB work in functions, like below.
public class MyObjectHandler
{
public bool Insert(MyObject obj)
{
using(SqlConnection conn = new SqlConnection(DbHandler.ConnectionString))
{
SqlCommand comm = new SqlCommand("OBJ_INSERT", conn);
comm.CommandType = CommandType.StoredProcedure;
comm.Parameters.Add(new SqlParameter("#Code", SqlDbType.NVarChar, 50) { Value = obj.Code });
comm.Parameters.Add(new SqlParameter("#Desc", SqlDbType.NVarChar, 150) { Value = obj.Desc });
comm.Parameters.Add(new SqlParameter("#UserId", SqlDbType.Int) { Value = obj.UserCreated.Id });
conn.Open();
int retVal = comm.ExecuteNonQuery();
conn.Close();
if(retVal > 0)
return true;
else
return false;
}
}
public bool Update(MyObject obj)
{
using(SqlConnection conn = new SqlConnection(DbHandler.ConnectionString))
{
SqlCommand comm = new SqlCommand("OBJ_UPDATE", conn);
comm.Parameters.Add(new SqlParameter("#Id", SqlDbType.Int) { Value = obj.Id });
comm.Parameters.Add(new SqlParameter("#Code", SqlDbType.NVarChar, 50) { Value = obj.Code });
comm.Parameters.Add(new SqlParameter("#Desc", SqlDbType.NVarChar, 150) { Value = obj.Desc });
comm.CommandType = CommandType.StoredProcedure;
conn.Open();
int retVal = comm.ExecuteNonQuery();
conn.Close();
if(retVal > 0)
return true;
else
return false;
}
}
public bool Delete(int Id)
{
using(SqlConnection conn = new SqlConnection(DbHandler.ConnectionString))
{
SqlCommand comm = new SqlCommand("OBJ_DELETE", conn);
comm.Parameters.Add(new SqlParameter("#Id", SqlDbType.Int) { Value = Id });
comm.CommandType = CommandType.StoredProcedure;
conn.Open();
int retVal = comm.ExecuteNonQuery();
conn.Close();
if(retVal > 0)
return true;
else
return false;
}
}
}
Problem is, as you can see I am using SqlConnection routine all the time.
I want to create a layer, which is a class that includes all the SQL libraries.
Would you offer me a general solution on this? Even a general idea will be enough on this.
For example, my function for Getting the data is easy:
public static DataTable GetDataTable(string spName)
{
DataTable resultsTable = new DataTable();
using(SqlConnection conn = new SqlConnection(DbHandler.ConnectionString))
{
SqlCommand comm = new SqlCommand(spName, conn);
comm.CommandType = CommandType.StoredProcedure;
conn.Open();
SqlDataAdapter adapter = new SqlDataAdapter(comm);
adapter.Fill(resultsTable);
conn.Close();
}
return resultsTable;
}
This is good enough, but I need a better solution to send parameters easily and with more flexibility. Seems like the only option is to send parameter name, type and length one by one. Would you recommend a design on this?

Consider using ORM with Repository pattern. ORMs are really great tools to build Data Access Layer. Dapper and NHibernate are my favorite; there are lot many other available.
Problem is, as you can see I am using "SqlConnection" routine all the time. I want to create a layer, which is a class includes all the Sql libraries. Would you offer me a general solution on this? Even a general idea will be enough on this.
General solution is ORM. General idea (without using ORM) could be to implement UnitOfWork pattern. Refer this answer. It is using Dapper ORM, but similar could be implemented with core ADO.NET. Repository pattern comes to rescue here. Instead of managing connection inside Repository, you can inject it from application. This way, your application gets total control over UnitOfWork and can use it the way suits for given situation.
I need a better solution to send parameters easier, and with more flexibility. Seems like the only option is to send parameter name, type and length one by one.
ORMs provide their own wrappers to accept the parameters; so it may help here. Without ORM, you can pass in Dictionay or similar and build parameter list inside your GetDataTable and pass it to ADO.NET call.

Related

Passing DropDownList value into SQL command in ASP.net

I have a DropDownList which gets it values from SQL table
I want to get the Average of the selected item (course in this case) from the dropDownList and to show it in a label :
This section works -
SqlConnection sqlConnection1;
sqlConnection1 = new SqlConnection(#"Data Source=HA\SQLEXPRESS; Initial Catalog=Grades1; Integrated Security=True");
SqlCommand Command = null;
Command = new SqlCommand("SELECT Course FROM GradesTable1", sqlConnection1);
Command.Connection.Open();
SqlDataAdapter dataAdapter = new SqlDataAdapter(Command);
DataTable dataTble1 = new DataTable();
dataAdapter.Fill(dataTble1);
if (dataTble1.Rows.Count > 0)
{
foreach (DataRow row in dataTble1.Rows)
{
ListItem course1 = new ListItem(row["Course"].ToString());
if (!DropDownList1.Items.Contains(course1))
{
DropDownList1.Items.Add(course1); // showing the 2 courses
}
}
}
Command.Connection.Close();
}
}
Here is the problem - (I get nothing, no data )
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
SqlConnection sqlConnection1;
sqlConnection1 = new SqlConnection(#"Data Source=HA\SQLEXPRESS; Initial Catalog=Grades1; Integrated Security=True");
SqlCommand Command = null;
Command = new SqlCommand($"SELECT AVG(Grade) FROM GradesTable1 WHERE Course = #course", sqlConnection1);
Command.Parameters.AddWithValue("#course", DropDownList1.SelectedItem);
Command.Connection.Open();
SqlDataReader sqlDataReader1 = Command.ExecuteReader();
if (sqlDataReader1.Read())
{
LabelAverage.Text = sqlDataReader1[0].ToString();
}
else
{
LabelAverage.Text = "No Data"; // doesn't get into here anyhow
}
}
EDIT
I tried several variations as $"SELECT AVG(Grade) AS "ClassAVG" FROM GradesTable1 WHERE Course = #course" and Command.Parameters.AddWithValue("#course", DropDownList1.SelectedItem.Text), or DropDownList1.SelectedValue
I believe the problem is with the DropDownlist values which being received from the SQL and are not hard coded.
Is there a correct way to this? is it possible without knowing what are the "Courses" in advanced?
Thanks for the answers, feel free to give your opinion.
I found out what was missing in the DropDownList in aspx page (not the aspx.cs page) -the AutoPostBack="true"
Adding that to DropDownList solved the problem.
// query = Sql query
query.Select(s => new MusteriNoktaComboItemDTO
{
Label = s.Adi,
Value = s.ID.ToString()
}).ToList();

ASP.NET 5 - DataSet, DataTable and friends

I'm creating a new webservice in ASP.NET 5 using the new .NET Core library, so far I've only hit an issue with using DataSet and DataTable.
According to this site they are not included at this moment in time, which is fine, but I don't know what alternatives I have at this time, so I'm just looking for some guidance.
I have the following code:
public string Get(string p_sUserId, string p_sUserPassword, int p_iCustId)
{
Select qrySelect = new Select();
using (SqlConnection conn = new SqlConnection(Startup.ConnectionString))
{
using (SqlCommand cmd = new SqlCommand(qrySelect.getData(), conn))
{
cmd.Parameters.AddWithValue("#Id", sTestId);
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
using (DataSet ds = new DataSet())
{
// foo
// bar
}
}
}
}
return "value";
}
How should I handle the data that is being return from the query? I need to build and return a string using the above data fetched from the query. Any help and guidance would be appreciated.
I believe SqlDataReader should work.
string sql = "SELECT * FROM Table";
using (SqlConnection con = new SqlConnection(Startup.ConnectionString)) {
con.Open();
using (SqlCommand command = new SqlCommand(sql, con)) {
using (IDataReader dr = command.ExecuteReader()) {
while (dr.Read()) {
//process data
}
}
}
}
DataTable and SqlDBAdapter are now supported using .NET Standard 2.0. Upgrade to VS2017 Preview, add System.Data.Common and System.Data.SqlClient nugets, and the code below should work. More detail at the blog post here -> https://blogs.msdn.microsoft.com/devfish/2017/05/15/exploring-datatable-and-sqldbadapter-in-asp-net-core-2-0/ . GitHub repo here -> https://github.com/jhealy/aspdotnetcore/tree/master/SqlClientPlay20 .
public static DataTable ExecuteDataTableSqlDA(SqlConnection conn, CommandType cmdType, string cmdText, SqlParameter[] cmdParms)
{
System.Data.DataTable dt = new DataTable();
System.Data.SqlClient.SqlDataAdapter da = new SqlDataAdapter(cmdText, conn);
da.Fill(dt);
return dt;
}

Stored Procedure in Orchard

Hi We are working on a project and i am trying to call a stored procedure. I have searched for the solution but i didn't find any way that how to call a stored procedure so can any one please tell me how to execute stored procedure.
How ever finally i am using the below code to execute the stored procedure and get the result.
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Suppress))
{
// temporary scope for new connection and setting stored procedure, parameters, and return RecordName list
using (SqlConnection cn = new SqlConnection(_settingsManager.LoadSettings().First().DataConnectionString))
{
if (cn.State == ConnectionState.Closed)
{
cn.Open();
}
const string storedProcedure = "usp_spName";
SqlCommand cmd = new SqlCommand(storedProcedure, cn);
cmd.Parameters.AddWithValue("#IsVerified", "value");
cmd.Parameters.AddWithValue("#page", "value");
// for out put parameter
cmd.Parameters.AddWithValue("#totalRows", 0);
cmd.Parameters["#totalRows"].Direction = ParameterDirection.Output;
cmd.CommandType = CommandType.StoredProcedure;
IDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
// To Get The Values of the result
int id=Convert.ToInt32(reader["Id"].ToString());
}
reader.Close();
try
{
// To Get the Out Put Perameter
totalRecords = (int)cmd.Parameters["#totalRows"].Value;
}
catch
{
totalRecords = 0;
}
cmd.Parameters.Clear();
cmd.Dispose();
cn.Close();
}
}
actually, I don't know about stored procedures, but you can call stored functions using code like examaple below. I'm new to C# and orchard, so may be my approach is not correct and good enough. At first you should get ISessionLocator object instance, using IOrchardServices, then create NHibernate ISession instance and then IQuery/ISQLQuery with CreateSQLQuery().
here is example code of Services class
public class ExampleService {
private readonly IOrchardServices _oServices;
public EParamsServices(IOrchardServices oServices) {
_oServices = oServices;
}
public float GetRegionPopulationDencity(int rId){
//resolve ISession locator (you can do this using dependencies in ctor)
ISessionLocator sl = _oServices.WorkContext.Resolve<ISessionLocator>();
//create session
ISession _session = sl.For(null);
// create raw SQL query
return _session.CreateSQLQuery(#"SELECT data.RegionDencity(:rId) as result")
.AddScalar("result", NHibernateUtil.Single)
.SetParameter<int>("rId", rId)
.List<float>()
.FirstOrDefault<float>();
}
}
I think you can exec stored procs the same way, just change SQL code do exec yourProcName and ExecuteUpdate() instead of List() method (I'm not sure in this part)
you also should add reference to NHibernate assembly to your project and add NHibernate & Orchard.Data to your using part.
You have to reference NHibernate and System.Data in your module , then you can use the below code
var cmd = _transactionManager.GetSession().Connection.CreateCommand();
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "MyStoredProcedure";
_transactionManager.GetSession().Transaction.Enlist(cmd);
cmd.ExecuteNonQuery();

Return nested complex types from WCF WebGet

I've created a wcf data service to return a List of complex type patient. I used the model browser to create a complex type for "Patient" and a complex type for "Contact". I'd like to add a "Contacts" property to "Patient", which would be a List.
How do I add a nested complex type list as a property and return it?
[WebGet]
public List<Patient> GetPatientByID(int tolid)
{
List<Patient> list = new List<Patient>();
// create pds user session record
SqlConnection conn = new SqlConnection("Data Source=server;Initial Catalog=db;User ID=<ID>;Password=<pwd>");
SqlCommand cmd = new SqlCommand();
try
{
// open the connection
conn.Open();
// configure the command
cmd.Connection = conn;
cmd.CommandText = "sp_tol_patient_select";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("tolid", tolid));
// execute the command and convert the decimal value
// returned by ExecuteScalar to an int to get new identity value
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
Patient itm = new Patient();
itm.MRN = reader["UNITNUMBER"].ToString();
itm.AccountNum = reader["ACCTNUM"].ToString();
itm.FullName = reader["PATNAME"].ToString();
itm.BirthDate = reader["BIRTHDATE"].ToString();
itm.Gender = reader["SEX"].ToString();
list.Add(itm);
}
return list;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
finally
{
cmd.Dispose();
conn.Close();
}
}

silverlight C# code

This is coded in Service.svc.cs file
[OperationContract]
public List<Branch> GetAllBranch()
{
List<Branch> Br = new List<Branch>();
using (SqlConnection con = new SqlConnection(myConnectionString))
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = "GetBranch";
cmd.Connection = con;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
Branch BrName = new Branch();
BrName.Name = Convert.ToString(dr["BranchName"]);
Br.Add(BrName);
}
dr.Close();
}
}
return Br;
}
public class Branch
{
public string Name { get; set; }
}
End of Service file Code----
This is coded in the Form
ServiceClient client= new ServiceClient();
test.GetAllBranchCompleted += (s, ea) =>
{
cboBranch.ItemsSource = ea.Result;
};
client.GetAllBranchAsync();
My requirement is I want to populate all the Names of the Branches that are present in my database.With this code the combobox for BranchName is getting populated but not with the Database records but something like this CRUD.ServiceReference1.ServiceBranch.
CRUD is my solution Name.
Please correct me with this..
Thanks
To get just the name to appear in your ComboBox you need to result a List<string>. Here you are returning a List<Branch>.
So you either need to rework your service code or just extract a list of strings from your ea.Result.
cboBranch.ItemsSource = ea.Result.Select(b => b.Name).ToList();
(from memory)