SQL Cache Dependency not working with Stored Procedure - asp.net

I can't get SqlCacheDependency to work with a simple stored proc (SQL Server 2008):
create proc dbo.spGetPeteTest
as
set ANSI_NULLS ON
set ANSI_PADDING ON
set ANSI_WARNINGS ON
set CONCAT_NULL_YIELDS_NULL ON
set QUOTED_IDENTIFIER ON
set NUMERIC_ROUNDABORT OFF
set ARITHABORT ON
select Id, Artist, Album
from dbo.PeteTest
And here's my ASP.NET code (3.5 framework):
-- global.asax
protected void Application_Start(object sender, EventArgs e)
{
string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString;
System.Data.SqlClient.SqlDependency.Start(connectionString);
}
-- Code-Behind
private DataTable GetAlbums()
{
string connectionString =
System.Configuration.ConfigurationManager.ConnectionStrings["UnigoConnection"].ConnectionString;
DataTable dtAlbums = new DataTable();
using (SqlConnection connection =
new SqlConnection(connectionString))
{
// Works using select statement, but NOT SP with same text
//SqlCommand command = new SqlCommand(
// "select Id, Artist, Album from dbo.PeteTest", connection);
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "dbo.spGetPeteTest";
System.Web.Caching.SqlCacheDependency new_dependency =
new System.Web.Caching.SqlCacheDependency(command);
SqlDataAdapter DA1 = new SqlDataAdapter();
DA1.SelectCommand = command;
DataSet DS1 = new DataSet();
DA1.Fill(DS1);
dtAlbums = DS1.Tables[0];
Cache.Insert("Albums", dtAlbums, new_dependency);
}
return dtAlbums;
}
Anyone have any luck with getting this to work with SPs?
Thanks!

i figured this out, need to set query options BEFORE creating the SP. got it working when i created the SP as follows:
USE [MyDatabase]
GO
set ANSI_NULLS ON
set ANSI_PADDING ON
set ANSI_WARNINGS ON
set CONCAT_NULL_YIELDS_NULL ON
set QUOTED_IDENTIFIER ON
set NUMERIC_ROUNDABORT OFF
set ARITHABORT ON
go
create proc [dbo].[spGetPeteTest]
as
select Id, Artist, Album
from dbo.PeteTest
GO

You are not returning data from the cache every time. It should be like this:
if (Cache["Albums"]!=null)
{
return (DataTable) Cache["Albums"];
}
else
{
// you need to write coding from database.
}

Another cause can be this in a SQL statement:
AND dbo.[PublishDate] <= GetDate()
The SQLCacheDependency will behave as if the underlying data has changed even if it hasn't, since GetDate() is dynamic (equally if you were to pass DateTime.Now via a #parameter).
This was not obvious to me after re-writing my proc following all the good suggestions above, also not forgetting also to remove "SET NOCOUNT ON" from the proc. SQLCacheDependency expires the cache if the data changes OR the query parameters values change, which makes sense I suppose.

For me using something like this in the stored proc didn't work.
select id, name from dbo.tblTable;
I had to explicitly put in the references like this.
select dbo.tblTable.id, dbo.tblTable.name from dbo.tblTable;

SQL caching won't work if you use select *, also you need to make sure you put dbo (or relevant schema) in front of your table name.
You can also check SQL profiler to verify if your sql is run hope will help you etc....

Note that you cannot use
with (NOLOCK)
in the stored procedure or the the dependency will remain constantly invalid.
This does not appear to be mentioned in the documentation as far as I can tell
I realise that the original poster did not do this but anyone coming here that has the problem stated in the title may have done this so I thought it was worth mentioning.

Related

Stored procedure not working

I have trouble converting this to stored procedure
//The string included in the sql statement:
string employer = Session["Employer"].ToString();
then the sql statement
update tblWorkData set EmployerName='"+txtemployername.text+"' where EmployerName='"+Employer+"' //the string above
This works fine in asp.net
But when I turn it into stored procedure,
create proc updateWork
#EmployerName nvarchar(max)
as
begin
update tblWorkData set EmployerName=#EmployerName where EmployerName=#EmployerName
end
Now when I execute the sp on asp.net,
string update = "updateWork '"+employer+"','"+txtemployername.text+"'";
I got an error saying "too many arguements". What should I do?
Your stored procedure only takes one argument and you're calling it with two. To fix this you need to alter the procedure to take two arguments like this:
create proc updateWork
#EmployerName nvarchar(max),
#Employer nvarchar(max)
as
begin
update tblWorkData set EmployerName=#EmployerName where EmployerName=#Employer
end
I changed the whereclause as I guess you meant it to be. As it was before it didn't actually do anything at all.
On a side note you might want to look into how to properly call procedures and how to add parameters in a way that isn't vulnerable to SQL injection.
You have to connect to the database in order to execute sql statements:
string employer = Session["Employer"].ToString();
// assume connectionString is a valid connection string
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = connection.CreateCommand();
command.CommandText = "updatework";
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#EmployerName", employer);
command.ExecuteNonQuery();
}

Binding Checklistbox with SqlServerDatabase

I want to Bind a checklistbox with Database in sqlserver2008. I am working in asp.net C# on a user control Module. I wrote a code. i want to know whether the code is perfact or not and also want to know that in which event i should place this code to get proper output.
{
int Post_Id = int.Parse(ViewState["ID"].ToString());
SqlConnection cn1 = new SqlConnection();
cn1.ConnectionString=
ConfigurationManager.ConnectionStrings["SiteSqlServer"].ConnectionString;
SqlDataAdapter da = new SqlDataAdapter("SelectTags", cn1);
DataTable ds = new DataTable();
SqlCommand cmnd1 = new SqlCommand("SelectTags", cn1);
cmnd1.Parameters.AddWithValue("#Post_Id",Post_Id);
cmnd1.CommandType = CommandType.StoredProcedure;
cn1.Open();
cmnd1.ExecuteNonQuery();
da.Fill(ds);
cn1.Close();
foreach (DataRow dr in ds.Rows)
{
String field1 = dr["Tag_Name"].ToString();
CheckBoxList2.Items.Add(field1);
CheckBoxList2.DataBind();
}
}
SQL query for sql server 2008
GO
/****** Object: StoredProcedure [dbo].[InsertPost2Tag] Script Date: 04/02/2013 09:47:01 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Alter PROCEDURE [dbo].[SelectTags]
-- Add the parameters for the stored procedure here
#Post_Id int
AS
BEGIN
SELECT mst_Tag.Tag_Name FROM mst_Tag INNER JOIN Post2Tag ON mst_Tag.tagId = Post2Tag.Tag_Id Where Post2Tag.Post_Id=#Post_Id
END
GO
Do this in page load witin
if(!ispostback){
CheckBoxList2.DataSource = ds; //This is the dataset that you fill from your stored procedure;
CheckBoxList2.DataTextField = "Tag_Name";
CheckBoxList2.DataValueField = "Tag_Name_Id";
CheckBoxList2.DataBind();
}
and take one more parameter Tag_Name_Id in your sp query..
SELECT mst_Tag.Tag_Name,Tag_Name_Id FROM mst_Tag INNER JOIN Post2Tag ON mst_Tag.tagId = Post2Tag.Tag_Id Where Post2Tag.Post_Id=#Post_Id
Remove this from your code
foreach (DataRow dr in ds.Rows)
{
String field1 = dr["Tag_Name"].ToString();
CheckBoxList2.Items.Add(field1);
CheckBoxList2.DataBind();
}
Hope this helps... If it is what you were asking for?
No need to do any thing Just choose data source for check list box and set the session variable with selected value of grid view in its selected index changed event.
It worked for me... and too easy to implement.

Calling stored procedure from asp.net doesn't work

I wrote a stored procedure to update PAID column in tblUser, and that stored proceudre works perfectly,
Code:
#buyer_email varchar(50),
#payment bit
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
update tblUser set paid=#payment where email = #buyer_email
END
but when I call it from my asp.net app then it doesn't update the Paid column, even if I try simple update statement in my asp.net code but that also doesn't update the column.
String userEmail_send = (Convert.ToString(Request.QueryString["emailAdmin"]));
String conString = "Data Source=COSANOSTRA; MultipleActiveResultSets=true; Initial Catalog=Waleed_orsfinal;Integrated Security=True";
try
{
con.Open();
if (userEmail_get.Replace("'", string.Empty) == userEmail_send.Replace("''", string.Empty))
{
//String query1 = "update tblUser Set paid=1 where email='" + userEmail_send + "' ";
SqlCommand sqlcom1 = new SqlCommand("submitPaypalPayment", con);
sqlcom1.CommandType = CommandType.StoredProcedure;
sqlcom1.Parameters.Add("#buyer_email", SqlDbType.VarChar).Value = userEmail_send;
sqlcom1.Parameters.Add("#payment", SqlDbType.Bit).Value= 1 ;
sqlcom1.ExecuteScalar();
hdr_msg_success.InnerText = "Congrats, You have paid successfully. Wait for an approval by an admin ";
Response.Write("<br/>"+" "+ "Matched=" +userEmail_send.Replace("''","'"));
}
else
{
hdr_msg_success.InnerText = "Something went wrong in matching Emails , Please confirm your Email";
}
}
catch (Exception exc)
{
Response.Write(exc.Message);
}
finally
{
con.Close();
}
The failure is likely due to your connectionstring security context.
Assuming you're running under IIS impersonation of the current web user is not the default behavior.
By specifying Integrated Security=True in your connectionstring you're telling SQL Server to accept the current Windows context as the user attempting to gain access to the database. This will be the IIS Application Pool account, not your own account, when running under IIS.
Try creating a SQL Server user name and password and specifying them in the connectionstring instead of using integrated security with a web application. You could alternatively set the Application Pool Windows Identity but that's something that's usually more cumbersome to maintain and migrate... There's also the option of allowing web user impersonation but that's even more unwieldy.
By the way, here are some other things to consider...
Store your connectionstring in a config file, not hardcoded (I understand that this may just be test code, but if not...)
Consider interacting with your stored procedure from ADO.net with something more like this in your use case.
using (SqlCommand sqlcom1 = new SqlCommand("dbo.submitPaypalPayment", con))
{
sqlcom1.CommandType = CommandType.StoredProcedure;
sqlcom1.Parameters.Add("#buyer_email", SqlDbType.VarChar) { Value = userEmail_send };
sqlcom1.Parameters.Add("#payment", SqlDbType.Bit) { Value= 1 };
sqlcom1.ExecuteNonQuery();
}
Based on what I read here, I seems like the values are not set correctly to the variables from the Request object.
Have you tried setting the break point and check what value is set to your userEmail_send variable from this statement
[String userEmail_send = (Convert.ToString(Request.QueryString["emailAdmin"]));]?
May be its not setting the right value for that variable.
Set the break point at this line sqlcom1.ExecuteScalar(); and check the parameter values.
You can do that by the ordinal position or by the name of the parameter as shown below:
By ordinal position sqlcom1.Parameters[0].Value or by name sqlcom1.Parameters["#buyer_email"].Value
do the same thing for your #payment parameter as well. Remember its ordinal position would be 1.
Hope, this helps... and good luck...

Return Two Data Sets

So I'm passing a ClientID to my DB and using that to look up all their details, then I want to use those details to also get all other users closely matching the details. I have all this written but my problem is I want to return the initial user's details also. For example;
Select Details = #UserDetails
from UnregisteredUserTable
where UserId = #UserID
Select BunchOfUsersWithMatchingData
from RegisteredUserTable
where UserDetails like #UserDetails
Obviously I've removed unnecessary info. But as you can see this returns all the data of the matching users but not the initial user's details. Could I use a CTE somehow?
UPDATE
Apologies, no idea my data access mattered. I'm doing pretty much the following atm but can change it no problem.
Dim results = thisObjectContext.MatcherSP(UserID)
For Each obj In results
TableData.Rows.Add(obj.IdNumber, obj.name,
obj.emailaddress1, obj.telephone1, obj.telephone2, obj.address1_line1,
obj.address1_line2)
Next
UPDATE 2
ok so I'm just using the two selects in my SP and it runs fine in SQL Server. But when I try to add it to my dbml in Visual Studio I get a strange error:
Unable to extract stored procedure 'dbo.MySP' because its result set contains muultiple anonymous columns.
Any ideas about that?
Well, this isn't VB code, but I will keep it as simple as possible.
Use a SqlDataAdapter to fill a data set. Results from both your select statements will populate different tables in the the DataSet.
cmd.CommandText = "MatcherSP";
cmd.CommandType = CommandType.StoredProcedure;
adapter = new SqlDataAdapter(cmd);
ds = new DataSet();
adapter.Fill(ds);
You can then access the data as follows:
tableA = ds.Tables[0];
tableB = ds.Tables[1];
You can use the SqlDataReader's nextresult() method.
using(SqlCommand cmd = new SqlCommand("NameOfSP",c))
{
cmd.CommandType = CommandType.StoredProcedure;
using(SqlDataReader d = cmd.ExecuteReader())
{
while(d.Read()){
//Result data from the first select
}
d.NextResult();
while(d.Read()){
//Result data from the second select
}
}
}
http://twogeeks.mindchronicles.com.dnpserver.com/?p=28&cpage=1#comment-37818
Brilliant article, outlined very clearly exactly what I wanted to do.

Parameterized query in Oracle trouble

I'm using Oracle.DataAccess rather than the obsolete System.Data.OracleClient and I seem to be having trouble passing multiple parameters to my update query
This works
OracleCommand.CommandText = "UPDATE db SET column1 = :param1 WHERE column2 = 'Y'"
OracleCommand.Parameters.Add(New OracleParameter("param1", "1234"))
But I want to be able to pass multiple parameters
Here's my full code
OracleConn.Open()
OracleCommand = OracleConn.CreateCommand()
OracleCommand.CommandText = "UPDATE db SET column1 = :param1 WHERE column2 = :param2"
OracleCommand.CommandType = CommandType.Text
OracleCommand.Parameters.Add(New OracleParameter("param1", "1234"))
OracleCommand.Parameters.Add(New OracleParameter("param2", "Y"))
OracleCommand.ExecuteNonQuery()
My SELECT query seems to work when passing multiple parameters but not the update one
Although I can't see anything wrong with your example, I wonder if you're being hit by the old BindByName problem. By default, ODP.NET binds parameters to the query in the order in which they are added to the collection, rather than based on their name as you'd like. Try setting BindByName to true on your OracleCommand object and see if that fixes the problem.
I've had this problem so many times that I use my own factory method to create commands which automatically sets this property to true for me.
Classic useless Oracle documentation here
To emulate the default behavior of the System.Data.OracleClient, you should set the OracleCommand to bind by name.
OracleCommand.BindByName = True
Try newing up your OracleParameter with a the type specified. Set the value of the object before adding it to the parameters list.
var param1 = new OracleParameter( "param1", OracleType.Int32 );
param1.Value = "1234";
OracleCommand.Parameters.Add( param1 );
Try this, hope it works. It does compile.
Not sure if you also have to send a commit...
I always do this sort of thing through a stored procedure, so I have a commit after the update statement in the stored procedure.
Harvey Sather
OracleConnection ora_conn = new OracleConnection("connection string");
OracleCommand ora_cmd = new OracleCommand("UPDATE db SET column1 = :param1 WHERE column2 = :param2", ora_conn);
ora_cmd.CommandType = CommandType.Text;
ora_cmd.BindByName = true;
ora_cmd.Parameters.Add(":param1", OracleDbType.Varchar2, "1234", ParameterDirection.Input);
ora_cmd.Parameters.Add(":param2", OracleDbType.Varchar2, "Y", ParameterDirection.Input);
ora_cmd.ExecuteNonQuery();
The first code block is correct: use a colon in front of the parameter name, but not in the first argument to OracleParameter.
If no errors are thrown, it could be that the UPDATE runs successfully, it just doesn't update any records based on the WHERE clause and its substituted parameter value. Try doing it on a test table with no WHERE clause in the UPDATE to make sure it does something.
Here's the type of structure I usually use (sorry, this is from memory) :
int rows = 0;
using ( OracleConnection conn = new OracleConnection(connectionString) ) {
using ( OracleCommand cmd = conn.CreateCommand() ) {
cmd.CommandText = "UPDATE table SET column1 = ':p1 WHERE column2 = :p2";
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue(":p1", p1Val);
cmd.Parameters.AddWithValue(":p2", p2Val);
rows = cmd.ExecuteNonQuery();
}
}
The key difference is the use of the AddWithValue - I don`t remember why I ended up using that, but do remember having problems with some of the other ways of doing it.

Resources