I have a web page that will allow customers to enter a date/time and I want to be able to stored that variable and then add to that time until Midnight, store that as a second variable and pass it to my sql server. Is there an easy way to do that?
Sure you can do:
var midnightDateNExtDay = DateTime.Now.AddDays(1).Date;
//AddDays moves time to next day
// Date should omit the time and make it midnight
Do you mean midnight previous or next day? Then, using this param, pass it to the stored procedure or query.
If you want the difference, you can do something like this and pass in the total seconds to sql server. This depends how you want to store this though on the sql end?
TimeSpan span = DateTime.Now.Subtract(DateTime.Now.AddDays(1).Date);
//do whatever with span.TotalSeconds
EDIT
It seems you also want to know how to send this into your procedure:
note this assumes connection strings setup in your app's config file. If not replace ConfigurationManager.ConnectionStrings[0].ConnectionString with "server=whatever;uid;whatever;pwd=whatever;" for your testing (I recommend you dont embed them in code though)
using (SqlConnection connection = new
SqlConnection(ConfigurationManager.ConnectionStrings[0].ConnectionString))
{
var midnight = DateTime.Now.AddDays(1).Date;
using (SqlCommand command = new SqlCommand("Proc_Whatever", connection))
{
command.Parameters.Add(new SqlParameter("#MidnightDate", midnight));
command.CommandType = CommandType.StoredProcedure;
connection.Open();
command.ExecuteNonQuery();
}
}
Related
System Scope
I have a database with a lot of users (over 50,000). At any time there may be 100-200 people logged in and actively using the system. The system is ASP.NET MVC 4, with Sql Server 2008 backend. For data access we are using Dapper.
Requirements
I am trying to build a notification component that has the following attributes:
When a new record is created in the [dbo.Assignment] table (with OwnerId = [Currently logged in user]), I need to update the Cache inside of an asp.net application.
I don't want to receive any notifications for users who are not actively online, as this would be a massive waste of resources)
Specific Questions:
Should I be using SqlDependency, SqlCacheDependency, or SqlNotification?
Assuming that we are using SqlDependency, how would I remove the Dependency.OnChange handler when user has logged out.
Any code samples would be much appreciated, as this has consumed the whole part of my day trying to figure it out.
Here is the current code
public IList<Notification> GetNotifications(string userName)
{
Cache o = HttpContext.Current.Cache;
if (o["Notifications_" + userName] == null)
{
var notifications = new List<Notification>();
using (var cn = new SqlConnection(getSQLString()))
{
using (var cmd = cn.CreateCommand())
{
var parameter = new SqlParameter("Employee_Cd", SqlDbType.Char, 30) { Value = userName };
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "Notifications.Assignments";
cmd.Parameters.Add(parameter);
cmd.Notification = null;
var dependency = new SqlCacheDependency(cmd);
cn.Open();
using (var dr = cmd.ExecuteReader())
{
// this is where you build your cache
while (dr.Read())
{
var obj = new Notification();
obj.Name = dr["Name"].ToString();
notifications.Add(obj);
}
dr.Close();
}
HttpContext.Current.Cache.Insert("Notifications_" + userName,
notifications,
dependency,
DateTime.Now.AddDays(1D),
Cache.NoSlidingExpiration);
}
}
}
return (List<Notification>) o["Notifications_" + userName];
}
Note: I am not experienced with using SqlDependencies, as I have never really needed to use them until today. It's very possible that I am overlooking something important.
I didn’t really use any of these techniques but here are some alternatives that you can create yourself that will do the job just as good.
If you need to update cache every time new record is inserted into dbo.Assignment table why not create OnInserted event in your data access layer that will notify the cache object to refresh?
Another thing you can to is to create INSERT trigger in Assignemt table and another table that can look like this dbo.Cache (LastUpdate datetime). Trigger will insert value into Cache table and your application cache can ping this table like every X mins or X seconds to see if cache update is required.
If you need to refresh the cache immediately after record is inserted triggers might be an overkill because you’d have to ping Cache table probably every second but if you have 200 online users at a time that probably won’t make much of a difference in DB performance.
There is a lot of work if you want to implement these for a lot of tables but since this is only one table this might turn out to be faster way than implementing built in cache mechanisms.
I have an ASP.NET page that needs to push a little data to an MS Access 2003 database. The process requires a Select on one record, Inserting one new record and Updating one record. I am connecting to the Access database via an OleDbConnection connection. So far, the Select and Insert functions are working exactly as expected (so I know my connection is good). The Update, however, fails to update any rows. The function to update the record looks like this:
public static int UpdateDeviceDates(int deviceId, DateTime nextTestDate)
{
var conn = DbConnect.AccessConnection();
var sqlString = WebConfigurationManager.AppSettings["UpdateDeviceDates"];
using (var cmd = new OleDbCommand(sqlString, conn))
{
cmd.Parameters.AddWithValue("#DeviceID", deviceId);
cmd.Parameters.AddWithValue("#NextTestDate", nextTestDate);
cmd.CommandType = CommandType.Text;
conn.Open();
var result = cmd.ExecuteNonQuery();
return result;
}
}
The sqlString pulled back from the web.config file looks like this:
UPDATE tblDevice
SET tblDevice.NextTestDate = #nextTestDate,
tblDevice.FirstNoticeDate = Null,
tblDevice.SecondNoticeDate = Null
WHERE DeviceID=#deviceId;
This query works fine if you paste it into a new Access query window and hit run, so I know the syntax is correct. I have done quite a bit of testing and figured out that it is the #nextTestDate field that is causing it to fail. When I took that out of the SQL string, it updated the record as expected. This is disconcerting, because the date I pass through to the Insert function works just fine.
I have looked around quite a bit and the closest I found to an answer was "Can't update date in aspx to a MS-ACCESS table". The main answer there was to change the parameter to a ShortDateString. I tried that to no effect. It was also suggested to bracket the date in #, since that is what Access does in its own queries. Unfortunately, that didn't work either.
I don't know why either of these should have been necessary, because the date comes through in exactly the same format as in the Insert statement and that works fine. I'm at my wits end here because the only thing I've found to make that query work is to remove the date parameter (which would defeat the main purpose of the query).
In your query, the parameters are in a different order, the order must match:
cmd.Parameters.AddWithValue("#NextTestDate", nextTestDate);
cmd.Parameters.AddWithValue("#DeviceID", deviceId);
To match:
UPDATE tblDevice
SET tblDevice.NextTestDate = #nextTestDate, <--- Param 1
tblDevice.FirstNoticeDate = Null,
tblDevice.SecondNoticeDate = Null
WHERE DeviceID=#deviceId; <--- Param 2
this is a method i was reading about #MSDN ,
my question is if for an example i would like to use it on a stored procedure
with the fact that the query of that stored procedure is already specifying columns to select from the table like following :
SELECT Columnsome, columnother, , , , ...FROM thisSQLdbTable
though i would like to implement the approach of that specific method , it seems very advanced from a little research i have made on
"the best way" available to extract data from SQL Server into Asp.net DataTable.
public static DataTable GetCustomerData(string dataSetName,
string connectionString)
{
DataTable table = new DataTable(dataSetName);
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlDataAdapter adapter = new SqlDataAdapter(
"SELECT CustomerID, CompanyName, ContactName FROM dbo.Customers", connection);
DataTableMapping mapping = adapter.TableMappings.Add("Table", "Customers");
mapping.ColumnMappings.Add("CompanyName", "Name");
mapping.ColumnMappings.Add("ContactName", "Contact");
connection.Open();
adapter.FillSchema(table, SchemaType.Mapped);
adapter.Fill(table);
return table;
}
}
or is it not the method to use if i am querying via SP that specifies the selected column
i could actually drop that stored procedure if it is not requiered to select /specify columns
the stored procedure is doing a specific calculation and updates the table with results of calculation then i am switching it's "MODE" to select results from the table that was updated.
what i did is recyceling (; giving it a parameter (bit type)
stored procedure then asks for the value of supplied bool / bit Parameter,
if its is status true it updates (doing its original task it was made for)
if its false its doing a select oporation so i am using it as i would with 2 separated commands
but now that i have search for a better way to extract data from db into a Data table
i give up on the two way SP and i will make a selection via the exaple above if they're not intended to be used thogether as with my current SP that does preselection when servs the GetCustomersData() above.
So the question is do i need to let the function to make the selection or can i serve it with my sp ready made selection to implemet it with GetCustomersData() in the way that it will only do rest of task and only mapp the columns that was preselected
Still a bit confused on your actual requirement but here goes:
I See you are using a direct query in your C# code, 'best way' would be to make a SP out of it then say:
SqlCommand command = conn.CreateCommand();
SqlDataAdapter sqlAdapter = new SqlDataAdapter(command);
command.CommandType = System.Data.CommandType.StoredProcedure;
command.CommandText = "sp_GetCustomerData";
Then after you have added parameters if needed do:
conn.Open();
sqlAdapter.Fill(dtResult);
conn.Close();
Where dtResult is Datatable.
So you do not need to do any mapping in this case, and since you are using a SP from the Database it will work faster than your direct query and you can change the query logic any time without the need of re deploying your code.
Stored procedures are perfectly valid in this use case. however, if you want more of a properly mapped table, you have several options, some of which go beyond the use of DataTables.
You can use strongly typed DataSets or perhaps use an ORM (object relational mapper).
ref: Typed Datasets: http://msdn.microsoft.com/en-us/library/esbykkzb(v=vs.71).aspx
ref: What is an ORM : http://en.wikipedia.org/wiki/Object-relational_mapping
EXAMPLES OF ORM'S
ref: Entity Framework : http://msdn.microsoft.com/en-us/data/ef.aspx
ref: NHibernate: http://nhforge.org/
I've been building this project as the solo dev for a while, and while I'm comfortable in the front end and middle tier, I don't really think I'm doing the database the way I should be, and the reason why is because I simply don't really know of any other way. The way I'm currently getting data is by testing out queries in my MySQL workbench and copying and pasting the SQL as a string literal into a method that makes a call to the DB, pulls the data and hydrates my objects.
This hasn't really been a problem until recently, when I had to create a monster of a query and it got me thinking that maybe there's a better way to do this. I don't have a formal DAL separated out, so I know there's room for improvement there, but I was curious about what the correct way would be to store SQL strings. I assume there is a tool somewhere built into VS10 where I can manipulate and work with SQL as SQL instead of as a string.
You should be doing this in stored procedures. That will basically format and store your query. You set parameters that are passed in from your code, then read out the results.
Example:
The C# method:
private void SetNote()
{
const string sql = "sp_SelectControllerNoteByID";
using (var conn = MocSystem.GetMocDbConnection())
{
using (var comm = new SqlCommand(sql, conn))
{
comm.CommandType = CommandType.StoredProcedure;
comm.Parameters.Add(new SqlParameter("#ControllerNoteID", ControllerNoteId));
try
{
conn.Open();
using (var rdr = comm.ExecuteReader())
{
while (rdr.Read())
{
CommentText = rdr["NoteText"].ToString();
_commentor = new User(new Guid(rdr["NoteAuthor"].ToString()));
CommentDate = (DateTime)rdr["NoteDate"];
MocRequestId = (int)rdr["MocRequestID"];
}
}
}
catch (Exception ex)
{
HasError = true;
ErrorMessage += "\nThere was a problem building the note: " + ex.Message;
}
}
}
}
The stored procedure on the DBMS (sql server in this example):
ALTER proc [dbo].[sp_SelectControllerNoteByID]
#ControllerNoteID int
AS
SELECT
ControllerNoteID,
NoteText,
NoteDate,
NoteAuthor,
MocRequestID
FROM
ControllerNotes
WHERE
ControllerNoteID = #ControllerNoteID
So here we call the stored procedure which in this case is just a simple select statement, then we read it out into an object via ADO. Now, this way, you can modify your query without recompiling. Unless you add parameters, in which case you'll have to update those in your code as well.
I have a SQL query I'm running in an ASP.NET page. The final parsed SQL needs to contain a list of string values in the WHERE [columnname] IN [values] format. For example, the final query might look something like this:
SELECT PRODUCTNAME FROM PRODUCT WHERE PRODUCTCODE IN ('ABC','DEF','GHI','JKL', /* etc */);
However, the string values in the WHERE clause need to be dynamic. Normally I use parametrized queries to make my code convenient and safe, so conceptually I'd like to do something like this:
String[] productCodes = { "ABC", "DEF", "GHI", "JKL" };
SqlCommand cmd = "SELECT PRODUCTNAME FROM PRODUCT WHERE PRODUCTCODE IN (#ProductCodes)";
cmd.Parameters.Add("#ProductCodes", productCodes);
However, this sort of functionality doesn't appear to exist in .NET. How should I go about implementing this? I could use a foreach loop on the array and run a query with a single value as a parameter for each value, but there could potentially be a hundred or so different values in the array and it seems like querying them separately would be very inefficient.
I've read another question where someone suggested a solution for strongly-typed int parameters, but that method would make me nervous about SQL injection when used with String values, especially since the client may very well be able to influence the input values.
How would you implement this query functionality?
EDIT with DB Details:
The database is SQL Server 2005. Sorry for forgetting to mention that.
Create your base sql statement as a format, and add the parameters dynamically, and then set the values in a loop.
String[] productCodes = { "ABC", "DEF", "GHI", "JKL" };
string sqlFormat = "SELECT PRODUCTNAME FROM PRODUCT WHERE PRODUCTCODE IN ({0})";
var #params = productCodes.Select((id, index) => String.Format("#id{0}", index)).ToArray();
var sql = String.Format(sqlFormat, string.Join(",", #params));
using(var cmd = new DbCommand(sql))
{
for (int i = 0; i < productCodes.Length; i++)
cmd.Parameters.Add(new Parameter(#params[i], DbType.String, productCodes[i]));
// execute query
}
Just an idea:
String[] productCodes = { "ABC", "DEF", "GHI", "JKL" };
SqlCommand cmd = "SELECT PRODUCTNAME FROM PRODUCT WHERE PRODUCTCODE IN (";
for (int i=0;i<productCodes.Length;i++) {
cmd.CommandText += "#" + productCodes[i] + ",";
cmd.Parameters.Add("#" + productCodes[i], productCodes[i]);
}
cmd.CommandText = cmd.CommandText.SubString(0, cmd.CommandText.Length-1);
cmd.CommandText += ");"
Probably not the best way, but I guess this is how I would try it.
For the record, querying the hundred or so values in the array "not separately" could also be inefficient (though not as inefficient as a hundred or so round trips to the SQL Server). However, parameterizing the query helps a bit because you can prepare the same query and execute it several times. A stored procedure could be even better.
Any chance you can use Linq, or are you pre-.NET-3.5?
If you can't use Linq, and you absolutely must go this route, try the following:
SqlCommand cmd = "SELECT PRODUCTNAME FROM PRODUCT WHERE PRODUCTCODE = #ProductCode";
cmd.Prepare();
List<string> results;
foreach (string code in productCodes)
{
cmd.Parameters.Clear();
cmd.Parameters.Add("#ProductCodes", DbType.VarChar).Value = code;
cmd.ExecuteQuery();
// Add code here to add the returned values to the results list. It's been
// a while since I've used ADO.NET, and I don't have time to look it up
// at the moment...
}
And then, you have your list of results.
You'rel looking for table-valued parameters. However, these weren't available for sql server until well after asp.net was widely adopted, and so the support for them in asp.net is limited.
What I recommend instead is to think of it like building a shopping cart. Users add items to the cart, and at some point you want to display all the items in the cart. In this case, the natural solution is that the shopping cart itself is in a database table rather. Rather than pulling down the items for the card to include as part of an "IN (?)" directive, you build this as a subquery for your directive instead: "WHERE X IN (SELECT X FROM ShoppingCart WHERE UserID= #UserID AND SessionKey= #SessionKey)". Even if you have hundreds of items added, the user is only so going to be so fast and the load per-insert is spread fairly evenly.
Of course, you're probably building something other than a shopping cart, but nevertheless your query will almost always fall into one of three categories:
The items for your list are selected by the user by hand, in which case you can still have each selection result in a new database record that can in turn be used in a subquery
It's data that's already available in your database, in which case you should still be able to use a sub query (and if you can't, it might be time to add a "category" column somewhere so that you can).
It's data that's hard coded into your app, in which case you can also code it into your query
The rare exception is when the query is triggered by another machine source, or you may also have a lot of code that you are reluctant to re-work to make this possible.
So if, for whatever reason, this approach doesn't cut it for you, the standard article on the subject for sql server (including a few alternatives) can be found here:
http://www.sommarskog.se/arrays-in-sql.html
This article really is the standard work on the subject, and is well worth your time.