I am having problem when doing retrieve function in 3-tier in C#. Here is the codes:
public DistributionStandardPackingUnits getSPUDetail(string distributionID)
{
DistributionStandardPackingUnits SPUFound = new DistributionStandardPackingUnits();
using (var connection = new SqlConnection(FoodBankDB.connectionString))
{
SqlCommand command = new SqlCommand("SELECT name, description, quantity FROM dbo.DistributionStandardPackingUnits WHERE distribution = '" + distributionID + "'", connection);
connection.Open();
using (var dr = command.ExecuteReader())
{
while (dr.Read())
{
string name = dr["name"].ToString();
string description = dr["description"].ToString();
string quantity = dr["quantity"].ToString();
SPUFound = new DistributionStandardPackingUnits(name, description, quantity);
}
}
}
return SPUFound;
}
When I run in browser, it just won't show up any retrieved data. When I run in debugging mode, I realized that when it hits the while loop, instead of executing the dr.Read(), it simply just skip the entire while loop and return null values. I wonder what problem has caused this. I tested my query using the test query, it returns me something that I wanted so I think the problem does not lies at the Sql statement.
Thanks in advance.
Edited Portion
public static SqlDataReader executeReader(string query)
{
SqlDataReader result = null;
System.Diagnostics.Debug.WriteLine("FoodBankDB executeReader: " + query);
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand(query, connection);
connection.Open();
result = command.ExecuteReader();
connection.Close();
return result;
}
I have a table with an identity column.
Using Massive with code like this
var table = new Categories();
var newID = table.Insert(new {CategoryName = "Buck Fify Stuff", Description = "Things I like"});
then
table.Scalar("select scope_identity()");
returns DBNull :(
What do I need to do different to get the actual inserted identity value
The MSDN documentation states that SCOPE_IDENTITY:
"retrieves the last identity values that are generated in any table in the current session"
Looking at the Massive source code, it appears that every call to Scalar() opens a new connection:
/// <summary>
/// Returns a single result
/// </summary>
public virtual object Scalar(string sql, params object[] args) {
object result = null;
using (var conn = OpenConnection()) { // <-- see this ...
result = CreateCommand(sql, conn, args).ExecuteScalar();
}
return result;
}
...
/// <summary>
/// Returns and OpenConnection
/// </summary>
public virtual DbConnection OpenConnection() {
var result = _factory.CreateConnection();
result.ConnectionString = ConnectionString;
result.Open(); // <-- ...and this
return result;
}
Therefore, every time you are doing table.Scalar("select scope_identity()"); you are actually doing this in a new connection (which means a different session/scope).
This explains the DBNull result.
But since you are already doing:
var newID = table.Insert(...)
you might want to inspect the value of newID after the insert happens; I hope you'll find something nice in there.
At least, that's what the code for Insert() leads me to believe:
public virtual dynamic Insert(object o) {
var ex = o.ToExpando();
if (!IsValid(ex)) {
throw new InvalidOperationException("Can't insert: " + String.Join("; ", Errors.ToArray()));
}
if (BeforeSave(ex)) {
using (dynamic conn = OpenConnection()) {
var cmd = CreateInsertCommand(ex);
cmd.Connection = conn;
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT ##IDENTITY as newID";
ex.ID = cmd.ExecuteScalar();
Inserted(ex);
}
return ex;
} else {
return null;
}
}
I use this pgm to get value from a column in xmlstring format named partinfo.which is one of the columns in table test.the partinfo column can be treated as another table containing many columns.and i want to read data from one of this column which is installed date in this case.but while executing i am getting a
sql exception: Cannot find either column "partinfo" or the user-defined
function or aggregate "partinfo.query", or the name is ambiguous.how
can i solve this.
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
try {
SqlConnection con = new
SqlConnection("Data Source=NIP007\\SQLEXPRESS;
Initial Catalog=test;User ID=sa;Password=nest123#!");
con.Open();
string query = "SELECT [partinfo].query('.//InstalledDate').value('.','VARCHAR(MAX)')FROM [test]";
SqlCommand cmd = new SqlCommand(query, con);
// StringBuilder builder=new StringBuilder();
// string PartInfo=string.Empty;
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
string str5 =dr.ToString();
if (!string.IsNullOrEmpty(str5))
{
textBox1.Text=str5;
}
}
}
catch(Exception ex)
{
}
}
}
}
It is not clear what exactly where your error lies because, your SQL should work ok (Demo Here) and not return an error, although I am not sure the output is what you would want as it just concatenates all the installed dates in the XML as one long string:
As said in my previous answer if you have multiple Installed Dates per row, you will want to use CROSS APPLY TO get the installed dates as separate rows.
Demo SQL using CROSS APPLY
If you really want the dates concatenated to one string then I'd suggest using a string builder to do this:
try
{
string query = #"SELECT InstalledDate = x.value('InstalledDate[1]', 'DATETIME')
FROM dbo.Test
CROSS APPLY PartInfo.nodes('/DocumentElement/PartInfo') p (x);";
using (var con = new SqlConnection("Data Source=NIP007\\SQLEXPRESS;Initial Catalog=test;User ID=sa;Password=nest123#!"))
using (var cmd = new SqlCommand(query, con))
{
con.Open();
using (var dr = cmd.ExecuteReader())
{
var builder = new StringBuilder();
while (dr.Read())
{
string str5 = dr.GetString(0);
if (!string.IsNullOrEmpty(str5))
{
builder.Append(str5 + ",");
}
}
textBox1.Text = builder.ToString();
}
}
}
catch (Exception ex)
{
}
If this doesn't help can you post the DDL of your table Test and some sample data.
Thanks
I'm now developing big government application with entity framework. at first i have one problem about enable SQL application role. with ado.net I'm using below code:
SqlCommand cmd = new SqlCommand("sys.sp_setapprole");
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = _sqlConn;
SqlParameter paramAppRoleName = new SqlParameter();
paramAppRoleName.Direction = ParameterDirection.Input;
paramAppRoleName.ParameterName = "#rolename";
paramAppRoleName.Value = "AppRole";
cmd.Parameters.Add(paramAppRoleName);
SqlParameter paramAppRolePwd = new SqlParameter();
paramAppRolePwd.Direction = ParameterDirection.Input;
paramAppRolePwd.ParameterName = "#password";
paramAppRolePwd.Value = "123456";
cmd.Parameters.Add(paramAppRolePwd);
SqlParameter paramCreateCookie = new SqlParameter();
paramCreateCookie.Direction = ParameterDirection.Input;
paramCreateCookie.ParameterName = "#fCreateCookie";
paramCreateCookie.DbType = DbType.Boolean;
paramCreateCookie.Value = 1;
cmd.Parameters.Add(paramCreateCookie);
SqlParameter paramEncrypt = new SqlParameter();
paramEncrypt.Direction = ParameterDirection.Input;
paramEncrypt.ParameterName = "#encrypt";
paramEncrypt.Value = "none";
cmd.Parameters.Add(paramEncrypt);
SqlParameter paramEnableCookie = new SqlParameter();
paramEnableCookie.ParameterName = "#cookie";
paramEnableCookie.DbType = DbType.Binary;
paramEnableCookie.Direction = ParameterDirection.Output;
paramEnableCookie.Size = 1000;
cmd.Parameters.Add(paramEnableCookie);
try
{
cmd.ExecuteNonQuery();
SqlParameter outVal = cmd.Parameters["#cookie"];
// Store the enabled cookie so that approle can be disabled with the cookie.
_appRoleEnableCookie = (byte[]) outVal.Value;
}
catch (Exception ex)
{
result = false;
msg = "Could not execute enable approle proc." + Environment.NewLine + ex.Message;
}
But no matter how much I searched I could not find a way to implement on EF.
Another question is: how to Add Application Role to Entity data model designer?
I'm using the below code for execute parameter with EF:
AEntities ar = new AEntities();
DbConnection con = ar.Connection;
con.Open();
msg = "";
bool result = true;
DbCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = con;
var d = new DbParameter[]{
new SqlParameter{ ParameterName="#r", Value ="AppRole",Direction = ParameterDirection.Input}
, new SqlParameter{ ParameterName="#p", Value ="123456",Direction = ParameterDirection.Input}
};
string sql = "EXEC " + procName + " #rolename=#r,#password=#p";
var s = ar.ExecuteStoreCommand(sql, d);
When run ExecuteStoreCommand this line return error:
Application roles can only be activated at the ad hoc level.
I do it the following way (assuming Database First):
I create the DbContext from the db and call it MyEntitiesBase
I inherit from MyEntitiesBase to create MyEntities with the following code:
public partial class MyEntities : MyEntitiesBase
{
private byte[] appRoleCookie;
private void SetAppRole()
{
try
{
appRoleCookie = Database.SqlQuery<byte[]>(
#"
DECLARE #cookie VARBINARY(8000)
DECLARE #r INT
EXEC sp_setapprole 'user', 'pass', #fCreateCookie = true, #cookie = #cookie OUTPUT
SELECT #cookie").First();
}
catch
{
throw new AuthenticationException();
}
}
private void UnSetAppRole()
{
bool failed = Database.SqlQuery<bool>("DECLARE #result BIT; EXEC #result = sp_unsetapprole #cookie = " + appRoleCookie.ToHexadecimalString() + "; SELECT #result").First();
if (failed)
throw new SecurityException();
}
public MyEntities() : base()
{
Database.Connection.Open();
SetAppRole();
}
private bool disposed = false;
protected override void Dispose(bool disposing)
{
if (disposed)
return;
UnSetAppRole();
Database.Connection.Close();
disposed = true;
base.Dispose(disposing);
}
}
Where ToHexadecimalString is an extension method for IEnumerable<byte>, as follows:
public static class BytesExtensions
{
public static string ToHexadecimalString(this IEnumerable<byte> bytes)
{
return "0x" + string.Concat(bytes.Select(b => b.ToString("X2")));
}
}
And that's it. Works with connection pooling on and everything. You just use this inherited version instead of the one generated by EF.
Basically what you are doing is calling a stored procedure.
Entity Framework has functionality to excute stored procedures. Here is an explaination with a video: http://msdn.microsoft.com/en-us/data/gg699321.aspx
If your scrol down to the section "Using Import Functions to Map Stored Procedures" you will find the part that is relevant for you.
My question involves returning a specific value from a table in a database. I want to have it where after you login, it displays the name of the user's first and last name.
The table looks like this.
Person
UID(PK), FName, LName, Uname, Upass
How do I return just the Fname and LName so I can place it in a label?
Here is my current code. Keep in mind this is for the master page.
string strConn = WebConfigurationManager.ConnectionStrings["cloud2"].ConnectionString;
protected void btnlogin2_Click(object sender, EventArgs e)
{
string strCmd = "Select * From Person Where uname = #uname and upass = #upass";
SqlConnection objConn = new SqlConnection(strConn);
SqlCommand objCmd = new SqlCommand(strCmd, objConn);
objCmd.Parameters.AddWithValue("#uname", txtusername.Text);
objCmd.Parameters.AddWithValue("#upass", txtpassword.Text);
using (objConn)
{
objConn.Open();
SqlDataReader objDR = objCmd.ExecuteReader();
if (objDR.HasRows)
{
btnlogin2.Visible = false;
txtusername.Visible = false;
txtpassword.Visible = false;
Response.Redirect("member.aspx");
lblLogin.Text = "Logged in as: Test " ; //Display login name?
}
else
{
btnlogin2.Text = "Failed";
}
}
}
First I'd refactor your logic a bit to maintain UI VS database calls a bit separate. Secondly refactor your code to retrieve first and last name that uses code for your connection string, username, password, and outputs firstname and lastname.
string firstName, lastName;
if(ValidateUser(txtusername.Text, txtpassword.Text, out firstName, out lastName)
{
//put your UI Logic and redirect in here
lblLogin.Text = "Welcome: " + firstName + " " + " lastName;
}
else
{
//login faild code
}
private bool ValidateUser(string strConn, string username, string password, out string firstName, out string lastName)
{
firstName = string.Empty;
lastName = string.Empty;
using (var con = new SqlConnection(strConn))
using (var cmd = con.CreateCommand())
{
cmd.CommandText = "Select * From Person Where uname=#uname and upass=#upass";
cmd.Parameters.AddWithValue("#uname", username);
cmd.Parameters.AddWithValue("#upass", password);
con.Open();
using (var r = cmd.ExecuteReader())
{
if (r.Read())
{
firstName = r["FName"].ToString();
lastName = r["LName"].ToString();
return true;
}
else
{
return false;
}
}
}
}
I would do three things:
separate your UI logic from the database logic - don't access your database directly in the middle of a button_Click event handler......
if you only need first and last name, then only select those two columns from the table!
put all the disposable objects like SqlConnection, SqlCommand, SqlDataReader into using(...) {...} blocks so that they will be properly disposed after use
So my code would look something like this:
UI layer:
protected void btnlogin2_Click(object sender, EventArgs e)
{
// call the database layer to get the first and last name
FirstAndLastName data = GetFirstAndLastName(txtusername.Text, txtpassword.Text);
if (data != null) // something was returned - show it
{
lblLogin.Text = string.Format("You're logged in as {0} {1}",
data.FirstName, data.LastName);
}
else
{
lblLogin.Text = "Not logged in....";
}
}
Database layer:
string strConn = WebConfigurationManager.ConnectionStrings["cloud2"].ConnectionString;
internal class FirstAndLastName
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
protected FirstAndLastName GetFirstAndLastName(string userName, string password)
{
FirstAndLastName result = null;
// if you only need FName und LName - then only select those two columns!
// don't just use SELECT * all the time because it's easy and because you're lazy
string strCmd = "SELECT FName, LName FROM dbo.Person WHERE uname = #uname AND upass = #upass";
// wrap everything into using blocks
using(SqlConnection objConn = new SqlConnection(strConn))
using(SqlCommand objCmd = new SqlCommand(strCmd, objConn))
{
objCmd.Parameters.AddWithValue("#uname", userName);
objCmd.Parameters.AddWithValue("#upass", password);
objConn.Open();
using(SqlDataReader objDR = objCmd.ExecuteReader())
{
if (objDR.Read())
{
result = new FirstAndLastName();
result.FirstName = objDR.GetString(objDR.GetOrdinal("FName"));
result.LastName = objDR.GetString(objDR.GetOrdinal("LName"));
}
}
}
return result;
}
string Name=objDR ["FName"].ToString() + ["LName"].ToString()
lblLogin.Text = "Logged in as:"+Name
You can read the instance of SqlDataReader in following way:
WebConfigurationManager.ConnectionStrings["cloud2"].ConnectionString; protected void btnlogin2_Click(object sender, EventArgs e) {
string strCmd = "Select * From Person Where uname=#uname and upass=#upass";
SqlConnection objConn = new SqlConnection(strConn);
SqlCommand objCmd = new SqlCommand(strCmd, objConn);
objCmd.Parameters.AddWithValue("#uname", txtusername.Text);
objCmd.Parameters.AddWithValue("#upass", txtpassword.Text);
using (objConn)
{
objConn.Open();
SqlDataReader objDR = objCmd.ExecuteReader();
if (objDR.Read())
{
string fName= (string)objDR["FName"];
string lName= (string)objDR["LName"];
btnlogin2.Visible = false;
txtusername.Visible = false;
txtpassword.Visible = false;
Response.Redirect("member.aspx");
lblLogin.Text = "Logged in as: Test "+fName+" "+lName; //Display login name?
}
else
{
btnlogin2.Text = "Failed";
}
}
}
Is your question how to return just the data you want from the query, or how to access it from the datareader?
It sounds like you might want ExecuteScalar(), and you can combine the fname and lastname fields in the query so you can just pull the one result:
string strCmd = "Select Fname + ' ' + LName From Person Where uname=#uname and upass=#upass";
SqlConnection objConn = new SqlConnection(strConn);
SqlCommand objCmd = new SqlCommand(strCmd, objConn);
objCmd.Parameters.AddWithValue("#uname", txtusername.Text);
objCmd.Parameters.AddWithValue("#upass", txtpassword.Text);
using (objConn)
{
objConn.Open();
var username = objConn.ExecuteScalar() as string;
if (!string.IsNullOrEmpty())
{
btnlogin2.Visible = false;
txtusername.Visible = false;
txtpassword.Visible = false;
Response.Redirect("member.aspx");
lblLogin.Text = "Logged in as: " + username ; //Display login name?
}
Edit: Just noticed a detail... you're setting lblLogin.Text after redirecting... so not thinking anyone's going to see it anyway. Could add it to the querystring though and display it on member.aspx...
You can do something like
lblLogin.Text = "Logged in as: " + objDR.GetString(dr.GetOrdinal("FName")) + " " + objDR.GetString(dr.GetOrdinal("LName"));
If memory serves, you probably also need to first call objDR.Read(); to start iterating over the datareader.