I'm just learning asp.net/C# and am building my first application.
In my application, I am rendering data from sql on almost every view.
My controllers are getting large, because every time I make a request, I'm using somthing like:
try
{
sqlConnection = new SqlConnection(dbConnectionString);
SqlCommand command = new SqlCommand("sp_Test", sqlConnection);
command.CommandType = CommandType.StoredProcedure;
sqlConnection.Open();
return command.ExecuteNonQuery();
sqlConnection.Close();
}
catch (SqlException ex)
{
Console.WriteLine("SQL Error" + ex.Message.ToString());
return 0;
}
Is there a way to turn the sql into a simple using block?
Maybe something like:
using(myConnection){
SqlCommand command = new SqlCommand("sp_Test", sqlConnection);
command.CommandType = CommandType.StoredProcedure;
}
There are many better approaches do it. You can create a SqlHelper class that can be used to execute stored procedures and SQL queries and also return DataReader and DataTable/DataSets.
public class SqlHelper
{
public SqlHelper(string connString)
{
}
public DataSet GetDatasetByCommand(string Command);
public SqlDataReader GetReaderBySQL(string strSQL);
public SqlDataReader GetReaderByCmd(string Command);
public SqlConnection GetSqlConnection();
public void CloseConnection();
}
You can see one such sample here:
http://www.nullskull.com/a/1295/sql-helper-class-in-c.aspx
If you want more advanced approach you can go for Enterprise Library Data Access Block
http://msdn.microsoft.com/en-us/magazine/cc163766.aspx
The best thing to do is refactor that statement into a seperate method. It looks like the only thing that could vary is the name of the procedure.
So create an object with two properties, a boolean success and an error message.
Call the function and pass in the name of the sql command. Your function should run your repeated code in the try block based on the given procedure name, then return an object with true/false and an error message if the call failed. This should make your controllers much smaller. Example code for the controller:
var result = MyNewMethod("sp_Test");
if(!result.Success)
{
Console.WriteLine(result.ErrorMessage);
return 0;
}
Related
I have a class function where I'm trying to read data from a database table using the SqlDataReader. When the SqlCmd.ExecuteReader() is called, I see(upon debugging) that the resultView of the SqlDataReader says "Enumeration yielded no results". However, the SqlDataReader.Read() still returns true and therefore enters the while() code block.
The query executes correctly on SQL, and even changing the query to get data from other tables give the same results. Please note that I have several other functions in a separate class executing the similar code to get data from these same database tables and they work without any issue.
Another observation is that after the ExecuteReader() is called, the VisibleFieldCount field of the SQLDataReader has the value = 11, which is equal to the total number of columns in the Customer table. This suggests that the reader is able read atleast some of the data from the database.
Any suggestions or help will be appreciated. Please let me know if any more information is required.
I have tried simplifying the function code as much as possible by removing any code logic other than the data retrieval part for the ease of debugging.
public bool MatchPassword(string username, string enteredPassword)
{
bool loginSuccessful = false;
string returnedpasswordbinary;
DatabaseConnection databaseConnectionObj = new DatabaseConnection();
databaseConnectionObj.CreateDBConnection(); //Sets the connection string and opens database connection
string query = "SELECT * FROM dbo.Customers WHERE CustomerID='ALFKI';";
SqlCommand sqlCommandObj = new SqlCommand();
sqlCommandObj.CommandText = query;
sqlCommandObj.Connection = databaseConnectionObj.SqlConnectionObj1;
try
{
SqlDataReader sqlDataReaderObj = sqlCommandObj.ExecuteReader();
if (sqlDataReaderObj.HasRows)
{
while (sqlDataReaderObj.Read())
{
returnedPasswordBinary = sqlDataReaderObj[0].ToString();
}
}
}
catch (Exception ex)
{
throw ex;
}
return loginSuccessful;
}
Can you please set commandtype
command.CommandType = CommandType.Text;
In our project's current state, we have at least one method used to call each stored procedure that we have created on the database server. Since these methods are pretty lengthy, involving creating each SqlParameter and then passing them to the database connection, I was considering creating a method that would generalize the process for our needs.
This is what I've come up with so far:
public static void UpdateTableTest(string procedureName, params object[] paramList)
{
if (sessionID == -1)
GetActiveSession();
SqlConnection scn = new SqlConnection(GetConnectionString());
try
{
scn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = scn;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = procedureName;
SqlCommandBuilder.DeriveParameters(cmd);
for (int i = 0; i < paramList.Length; i++)
{
cmd.Parameters[i+1].Value = paramList[i];
}
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
throw ex;
}
finally
{
scn.Close();
}
}
Aside from problems that I will run in to for different query types, and for query types that I will need to return some data from, is there anything inherently wrong with this method of executing stored procedures? Should I stick with an individual method for each stored procedure?
You can consider using Enterprise library or
SQLHelpers
available online.
example
DataSet dsUserInfo = new DataSet();
dsUserInfo = SqlHelper.ExecuteDataSet("Select * from UserInfo", CommandType.Text);
MyDataGridview.DataSource = dsUserInfo.Tables[0];
Or if you want to get rid of this even, you can go for ORM like EF suggested by John
I am running unit tests and when I try to insert data in the database and getting it right after, I don't get anything (I have tried with DataAdapter and DataReader).
However when I put a 3 seconds sleep (even with 1 second it doesn't work...) between the insert and the select I get the result.
In SQL Server Profiler I can see the execution, the insert is well done and is completed about 10 miliseconds before the select begins.
I can't find out where this comes
The code looks like this :
Insert method
SqlCommand command = new SqlCommand(sqlTemplate);
command.Parameters.Add(Sql4oConstants.Sql4oIdParameterName, SqlDbType.UniqueIdentifier).Value = id;
command.Parameters.Add(Sql4oConstants.Sql4oTimestampParamterName, SqlDbType.DateTime).Value = DateTime.Now;
command.CommandTimeout = dataSourceDescription.CommandTimeout;
DatabaseManager.ExecuteNonQuery(dataSourceDescription.ConnectionString, command);
Get method
public static void Fill(string connectionString, DataTable table, SqlCommand command)
{
try
{
LogStorageWriter.WriteLogEntry(log, EStorageLevelLog.Debug, string.Format("Execute query: {0}", command.CommandText));
using (SqlConnection conn = new SqlConnection(connectionString))
{
command.Connection = conn;
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
{
adapter.Fill(table);
}
}
}
catch (InvalidOperationException e)
{
LogStorageWriter.WriteLogEntry(log, EStorageLevelLog.Error, string.Format("Exception : {0}", e.ToString()));
}
}
I solved it.
In fact, it was because my request used a CONTAINS. I then discovered that using a CONTAINS calls the SQL Server Indexer to fetch data. But the engine does not index data instantly.
That's why I had to wait 2 or 3 seconds to get my data back.
I have created a class to ease the use of SQL server within my app.
public static class SqlServer
{
public static void QueryNoReturn(string ConnectionString, string Query, SqlParameter[] Parameters, bool IsStoredProcedure)
{
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
// Create the command to run
SqlCommand command = new SqlCommand(Query, conn);
// If we are running a stored procedure
if (IsStoredProcedure)
command.CommandType = System.Data.CommandType.StoredProcedure;
// Add parameters if they exist
if (Parameters != null)
command.Parameters.AddRange(Parameters);
try
{
// Open the connection to the database
conn.Open();
// Execute the command and assign to the result object
command.ExecuteNonQuery();
conn.Close();
command.Parameters.Clear();
}
catch (SqlException sqlex)
{
throw new Exception(
string.Format("{0} \"{1}\"", IsStoredProcedure ? "Procedure" : "Query", Query),
sqlex);
}
}
}
}
If I am calling this static method many times a second (approx. 50) then will I see issues with thread safety?
I could easily create a Factory or some other instance specific object, but I went with this option out of simplicity.
Since you are not using any shared resources of the class, this appears to be "thread-safe".
This of course disregards any concurrency issues on the database itself.
You should wrap the SqlCommand creation in a using statements as well.
Since you are creating the SqlConnection in a using statement, you don't need to explicitly call Close on it, as it will be done when the connection is disposed.
No. You could get into thread safety problems when you access shared resources, but you don't do that (at least not in this method).
By the way, move the conn.Close(); to a finally clause, that way the connection is closed, even when you get an exception.
I have a very simple Update statement that will update mail server settings and network credentials info... Query works fine when I run it in Access but C# keeps giving me the error stating that my SQL Syntax is wrong ... I have a dataaccess layer (dal class) and Update instance method pasted belows ... But the problem must be sth else cuz I have updated lots of stuff this way but this time it just won't do .. any clues will be greatly appreciated. Thx in advance.
Update instance method in DAL class .. (this is supposed to be a Data Access Layer :) I'm just a management graduate :P
public int UpdateRow(string Query, bool isSP, params OleDbParameter[] args)
{
int affectedRows = -1;
using (con = new OleDbConnection(connStr))
{
using (cmd = con.CreateCommand())
{
cmd.CommandText = Query;
if (isSP)
{
cmd.CommandType = CommandType.StoredProcedure;
}
if (args != null)
{
foreach (OleDbParameter prm in args)
{
cmd.Parameters.Add(prm);
}
}
try
{
con.Open();
affectedRows = cmd.ExecuteNonQuery();
}
catch(OleDbException ex)
{
throw ex;
}
catch (Exception ex)
{
throw ex;
}
}
}
return affectedRows;
}
And the ASP.NEt codebehind that will do the updating =
protected void Update_Click(object sender, EventArgs e) {
DAL dal = new DAL();
string upt = string.Format("UPDATE [MailConfig] SET Server='{0}', Username='{1}', Password='{2}', AddressFrom='{3}', DisplayName='{4}'",server.Text,username.Text,password.Text,replyto.Text,displayname.Text);
dal.UpdateRow(upt,false,null);
LoadData();
}
peace!
Trying wrapping your field names in [ ]. I have had problems in the past with certain field names such as a username and password and count, etc, being recognized as reserved words and screwing up the sql giving me an error.
First off - don't use string.Format here. Use parameters, and add parameters to the command. Right now, you are wide open to SQL injection attacks. Think "Bobby Tables".
Re "stating that my SQL Syntax is wrong" - can you please quote the exact error?
First of all, you have no where clause in your Update, so it will update all rows, and violate key constraints causing an error, if you have any.
Second, running that kind of code makes you very vunerable to SQL Injection, if someone enters a username that has a sql command embedded in it, you could lose all your data.
You should use parameterized queries. You specify your parameters in the sql command with #paramname instead of using {4}, and then with the command object do accessCommand.parameters.AddWithValue("#paramname", value)
You are using a CommandType of StoredProcedure, but your query is not a stored procedure name, its a sql query without a where clause.
UPDATE [MailConfig]
SET Server='{0}',
Username='{1}',
Password='{2}',
AddressFrom='{3}',
DisplayName='{4}'"
So you need to remove the command type line, or change it to a correct command type CommandType.Text, and add a Where clause specifying what rows are to be affected.
I don't think Access even has Stored Procedures, so there's no using to use that command type with it.
An example of a command that does use stored procedures would be something like:
string sqlCommString = "QCApp.dbo.ColumnSeek";
SqlCommand metaDataComm = new SqlCommand(sqlCommString, sqlConn);
metaDataComm.CommandType = CommandType.StoredProcedure;
The command string for that type is just the name of the stored proc.