I want to refresh the data automatically when change to the database is made.
I used this documentation:
And made the code on page load as:
protected void Page_Load(object sender, EventArgs e)
{
conString = "Data Source=MITEJ5-PC\\MITEJTECHONOLY;Initial Catalog=SSISTestDatabase;Integrated Security=SSPI;";
SqlDependency.Start(conString);
using (SqlConnection connection =
new SqlConnection(conString))
{
using (SqlCommand command =
new SqlCommand(GetSQL(), connection))
{
SqlCacheDependency dependency =
new SqlCacheDependency(command);
// Refresh the cache after the number of minutes
// listed below if a change does not occur.
// This value could be stored in a configuration file.
int numberOfMinutes = 1;
DateTime expires =
DateTime.Now.AddMinutes(numberOfMinutes);
Response.Cache.SetExpires(expires);
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetValidUntilExpires(true);
Response.AddCacheDependency(dependency);
connection.Open();
gv.DataSource = command.ExecuteReader();
gv.DataBind();
}
}
}
private string GetSQL()
{
return "select Name,Age,Address from tlbStudent;";
}
But when I run this , and made changes in SQL table data, it is not reflecting it on grid automatically.
Where can I be wrong in above code???
Please help me.
First you need to understand how SqlDependency works. Read The Mysterious Notification for a short introduction. Once you learn that the real feature at work is Query Notifications, you can learn about the restrictions in place for queries using notifications, see Creating a Query for Notification. Once such restriction is:
The projected columns in the SELECT statement must be explicitly stated, and table names must be qualified with two-part names. Notice that this means that all tables referenced in the statement must be in the same database.
For future problems read Troubleshooting Query Notifications.
The problem in
private string GetSQL()
{
return "select Name,Age,Address from tlbStudent;";
}
the table name should be 2 parts ""
private string GetSQL()
{
return "select Name,Age,Address from dbo.tlbStudent;";
}
according to the documentation
The projected columns in the SELECT statement must be explicitly stated, and table names must be qualified with two-part names. Notice that this means that all tables referenced in the statement must be in the same database.
Related
Here is my code, it works when the database has the table "UserInformation"
public bool Save()
{
using (SqlConnection connection = new SqlConnection(ConnectionString)
{
connection.Open();
using (SqlTransaction transaction = connection.BeginTransaction())
{
try
{
using (var adapter = new UserInformationTableAdapter())
{
adapter.Connection = connection;
adapter.Transaction = transaction;
var table = new HelloDataSet.UserInformationDataTable();
HelloDataSet.UserInformationRow row = table.NewUserInformationRow();
row.UserName = userName;
row.Password = password;
row.Brithday = brithday;
table.Rows.Add(row);
adapter.Update(table);
transaction.Commit();
return true;
}
}
catch (Exception e)
{
transaction.Rollback();
return false;
}
finally
{
connection.Close();
}
}
}
However, when there is no table in the database, it will not create the "UserInformation" table in the database, it will jump to "catch" exception in line "adapter.Update(table);"
So my question is how can I create a new table in database if there is no "UserInformation" table in it. In addition, if the database already has the table "UserInformation" can I add a new column "Position" in that table?
Finally, I got the answer and want to share it out. First, I have to say that I put my question in a wrong way. What I really want is I have an application, and this application is connected with a database. However, I am allowed user to switch database. So, when the user switch to a new database I would like the application copy the entire database structure (not including the data) from the old one to the new one. Also, if I make some change (could be add a new column for one or more table, or add another new table) for the database in my application code, I would like every other database know the updates and make the same change by running my new application code.
So, here is my solution. I write a framework called "SchemaManager." It will create an additional table in each database, this table contains the version of the database. So, every time when I run my application the "SchemaManager" will check my hard code database version number with the database version number, if my hard code database version number is greater than the database version number, the "SchemaManager" will check the change and do the update for me.
I know my solution is not the best, but this is what I did. If anyone have anyother solution, please share with me and other people.
I have a project (with c# and SQLServer), that it should run on multiple clients and each client should communicate with a central SQL Server. All of the clients and the server are on the same local network.
Everything is ok, but... in some cases, when a insert query runs on a client, multiple duplicate records insert into sql server. This problem occurs rarely.
Below is the query. The query runs when a form is filled and a button click event trigers.
public static int insertSick(string firstname,string lastname,string mobile,string address)
{
using (SqlConnection connection = new SqlConnection(getConnectionString()))
{
string sql = "insert into TSick (Firstname,Lastname,MobileNumber,Address) values
(#fname,#lname,#mobile,#address)";
connection.Open();
SqlTransaction tran = connection.BeginTransaction();
SqlCommand command = new SqlCommand(sql, connection, tran);
command.Parameters.AddWithValue("fname", firstname);
command.Parameters.AddWithValue("lname", lastname);
command.Parameters.AddWithValue("mobile", mobile);
command.Parameters.AddWithValue("address", address);
int nRecord = command.ExecuteNonQuery();
tran.Commit();
return nRecord;
}
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
// check the text fields and validate them
insertSick(firstname,lastname,mobile,address);
}
The table is as below:
TSick :
- ID --> this column is an incremental identity
- Firstname
- Lastname
- Mobilenumber
- Address
Can someone tell me why in some cases instead of a single record multiple records inserted? How to solve? Do you think that it is a network related problem?
Thanks
It's almost certainly that the user clicks the button twice. You should disable the button as the first thing in your click event handler, and then enable it again at the appropriate time; what constitutes the "appropriate time" is up to you to decide.
Before from the insertion of data in table you can do validation of data whether data is duplicate or not.
First check which column is unique in your table, on the basis of unique column you can check the data otherwise make a composite key(if there is no unique column) in the table and verify the data before from insertion. If a data is duplicate through a message to user.
I want to insert values in "Navn" row and "Varenr" row in the DB table, when I'm clicking on a button. I have following code:
private void button2_Click(object sender, EventArgs e)
{
using (SqlConnection cn = new SqlConnection(#"Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Produkt.mdf;Integrated Security=True"))
{
try
{
SqlCommand cm = new SqlCommand();
cm.Connection = cn;
string col1 = textBox2.Text;
string col2 = textBox3.Text;
//generate sql statement
cm.CommandText = "INSERT INTO ProduktTable (Navn,Varenr) VALUES (#col1,#col2)";
//add some SqlParameters
SqlParameter sp_add_col1 = new SqlParameter();
sp_add_col1.ParameterName = "#col1";
//data type in sqlserver
sp_add_col1.SqlDbType = SqlDbType.NVarChar;
//if your data type is not number,this property must set
//sp_add_col1.Size = 20;
sp_add_col1.Value = textBox2.Text;
//add parameter into collections
cm.Parameters.Add(sp_add_col1);
//in your insert into statement, there are how many parameter, you must write the number of parameter
SqlParameter sp_add_col2 = new SqlParameter();
sp_add_col2.ParameterName = "#col2";
//data type in sqlserver
sp_add_col2.SqlDbType = SqlDbType.NVarChar;
//if your data type is not number,this property must set
//sp_add_col2.Size = 20;
sp_add_col2.Value = textBox2.Text;
//add parameter into collections
cm.Parameters.Add(sp_add_col2);
//open the DB to execute sql
cn.Open();
cm.ExecuteNonQuery();
cn.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
But unfortunately, my data table is still empty:
I have set a breakpoint on the ExecuteNonQuery function, and it is triggered, when pressing on the button:
My table definition:
Your connection string is causing this:
Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Produkt.mdf;Integrated Security=True"
|DataDirectory| Your database that is being updated in this method is in your App Data Directory while the one you are trying to retrieve data from is in your project folder...
|DataDirectory| is a substitution string that indicates the path to the database. DataDirectory also makes it easy to share a project and also to deploy an application. For my PC my App Data Directory is:
C:\Users\MyUserName\AppData\...
If you browse to this location and then go to following folders
...\Local\Apps\2.0\Data
You will be able to find your particular application directory probably stored with your assembly name, or some hash when you go there you will find it the database there is being updated just fine. This connection string is best for deployment.
You can also try this:
If you notice that Server Explorer is detecting all the databases on my PC and you can notice that there are couple of MINDMUSCLE.MDF files but all are at different paths, this is because there is one file in DEBUG directory, one in my PROJECT directory, one in my APP DATA directory. The ones starting with the numbers are stored in my APP DATA directories... If you select your respective database file and then run the SELECT query against it, you will get your data.
I made a tutorial some time ago. May be it will help you:
Check the value that ExecuteNonQuery is returning. It should return an int with the number of records affected by the SQL statement.
If it comes back with a value other than 0, then you know a record is being inserted somewhere. Before you close the connection, run a SQL query against the table to select all of the records and see if they come back through the code.
SELECT * FROM ProduktTable
If you get some records, then you may want to double check the database you're looking at through the IDE and the one your inserting records into through the code. It could be possible that you've got two different databases and you're querying one while inserting into another one.
Those are the steps that I would go through to help narrow down the issue and sounds like something I've probably done before. I hope it helps!
I am currently writing a small application to keep track of monetary ins and outs, something just to improve my general C# skills. For my Login Screen currently I have the following Code
private void Login_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'spendingInsAndOutsDataSet.Users' table. You can move, or remove it, as needed.
this.usersTableAdapter.Fill(this.spendingInsAndOutsDataSet.Users);
}
private void button1_Click(object sender, EventArgs e)
{
string userNameText = userName.Text;
string passwordText = password.Text;
foreach (DataRow row in spendingInsAndOutsDataSet.Users)
{
if (row.ItemArray[4].Equals(userNameText) && row.ItemArray[5].Equals(passwordText))
{
MessageBox.Show("Login Successful");
MainGUI newForm = new MainGUI();
this.Visible = false;
newForm.Show();
break;
}
else
{
userName.Text = String.Empty;
password.Text = String.Empty;
MessageBox.Show("Login Failed");
break;
}
}
}
What I am looking to do when the Login is Sucessful is to write the MachineName of the current PC to a field in Users table in my SQL Database. That way when I come to start creating records I can quickly find my UsersId (which is a foreign key in my Transactions table).
I know you can get the Active Machine Name using the System.Enviroments path but Im unsure exactly how to go about writing the update. I know how to do it using a SqlCommand but I am wondering if there is a simpler way using the DataRows I have used within the ForEach loop.
Thanks in advance, any questions let me know.
James
Assuming it is an Access database (If not then make the necessary changes):
Use an Adapter to fill a table with your results. Then compare the row columns with the information provided by the user. Don't forget to use parameters to avoid injections that may potentially ruin your database or expose your user's information to a hacker.
DataTable dt = new DataTable();
String sql = "SELECT * FROM users WHERE user = #user and password=#password"
OleDbConnection connection = getAccessConnection();
OleDbDataAdapter da = new OleDbDataAdapter(sql, connection);
da.SelectCommand.Parameters.Add("#user", OleDbType.VarChar).Value = userNameText;
da.SelectCommand.Parameters.Add("#password", OleDbType.VarChar).Value = password.Text;
try
{
connection.Open();
da.Fill(dt);
connection.Close();
}
catch(OleDbException ex)
{
connection.Close();
MessageBox.Show(ex.ToString());
}
if(dt.Rows.Count == 1)
return true; //username && password matches
else if(dt.Rows.Count == 0)
return false; // does not match
You could also use AddWithValue for your parameters.
da.SelectCommand.Parameters.AddWithValue("#user", userNameText);
getAccessConnection() is a predefined OleDbConnection function that has the connection to the database setup and creates a new instance of the connection for you (that I have created for myself).
public OleDbConnection getAccessConnection()
{
this.connection = new OleDbConnection();
this.connection.ConnectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source="
+ Classified.SOURCE + ";Jet OLEDB:Database Password="
+ Classified.PASS + ";";
return this.connection;
}
It is preferred to create classes for all of these functions for developers who may join in on the project. Also read up on C# test driven development as well.
Also it looks like your loop will break even if that one record fails, only allowing it to go to it's first record.
Onto creating your own data set and filling it with queried tables is also useful. Here is a brief example:
DataSet ds = new DataSet();
ds.Tables.Add(dt, "userSearchedTable");
ds.Tables["userSearchedTable"].Rows[0][1].ToString();
Then you can declare a specific data table within the set when ever you need to.
In your foreach loop, set the MachineName of the current PC on relevant row then at the end of the method call:
this.usersTableAdapter.Update(this.spendingInsAndOutsDataSet.Users);
This will update the database with the machine name
However looking at your code there are a few additional comments to make I'd like to add to improve what you have:
You are loading the entire data table and then checking it for the username and password. Really you query for the user ID in the database, load that single row and check the password. If you have many users, your current implementation will create a lot of network traffic.
Instead of:
foreach (DataRow row in spendingInsAndOutsDataSet.Users)
Consider using something like:
foreach (SpendingInsAndOutsDataSet.UsersRow row in spendingInsAndOutsDataSet.Users)
i.e. the strongly typed version of the data row object. This means you can use:
row.Username.Equals(userNameText)
instead of
row.ItemArray[4].Equals(userNameText)
Also if you are anticipating that this will be used over a network, you should look to encrypt the passwords.
I want to display information of user stored in a MS Access database. The user enters his userid and on clicking a button following function is called. But no data is being displayed. What am I doing wrong ?
System.Data.OleDb.OleDbConnection con;
System.Data.OleDb.OleDbDataAdapter da;
protected void Button1_Click(object sender, EventArgs e)
{
con = new System.Data.OleDb.OleDbConnection();
con.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;"
+ "Data Source=C:\\Users\\sam\\Desktop\\mydb.mdb";
con.Open();
string sql = "SELECT * From Leave where userid="+Textbox1.Text;
da = new System.Data.OleDb.OleDbDataAdapter(sql, con);
DataTable t = new DataTable();
da.Fill(t);
GridView1.DataSource = t;
con.Close();
}
You need to call GridView1.DataBind()
GridView1.DataSource = t;
GridView1.DataBind();
Just a side-note, it is good practice to wrap your connection with using
using(con = new System.Data.OleDb.OleDbConnection())
{
con = new System.Data.OleDb.OleDbConnection();
con.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;"
+ "Data Source=C:\\Users\\sam\\Desktop\\mydb.mdb";
con.Open();
...
...
}
This ensures your connection is properly disposed after use
You should use bind function:
protected void Button1_Click(object sender, EventArgs e)
{
con = new System.Data.OleDb.OleDbConnection();
con.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;"
+ "Data Source=C:\\Users\\sam\\Desktop\\mydb.mdb";
con.Open();
string sql = "SELECT * From Leave where userid="+Textbox1.Text;
da = new System.Data.OleDb.OleDbDataAdapter(sql, con);
DataTable t = new DataTable();
da.Fill(t);
GridView1.DataSource = t;
GridView1.DataBind();
con.Close();
}
First off, please, please please don't concatenate your WHERE parameters in your SQL. Use Parameters. Second, Add a "using System.Data.OleDb" statement at the top of your module, so that you are not having to type things like:
System.Data.OleDb.OleDbDataAdapter
Over and over again.
Try the following code. Personally, when I have to work with data tables and such, I prefer to avoid all the DataAdapter nonsense, and keep it as simple as possible.
Note in the code below:
the "using" blocks. These place the variables created within them inside their own scope, and take care of disposal and such for you.
I used an OleDb Parameter instead of concatenating criteria. This is a much safer way to do things, and creates much cleaner and more readable code as well, especially in cases where you have several criteria in your WHERE clause.
I assume your UserID input is a string, since you are grabbing the value from a Textbox. If it is in fact an int value (such as an auto-incrementing id in MS Access) you will need to use an int data type instead. You may have to mess with it a little. When you are still figuring this stuff out, it can be a bit painful. However, using parameters increases security and maintainability.
Once you have obtained a data table as the return from the MyUsers method, you should be able to simply set the data source of your Gridview. If you have difficulties still, do as Steve suggests and check the Autogenerate columns property in the designer, or set it in code.
Not that I have moved the connection string to the project Properties/Settings. You should find this in the solution designer. Place your connection string there, in one spot, and you can obtain it from anywhere in your code. If you later change the connection string (such as moving your Db to another computer, server share, etc) you need only change it in one place.
SAMPLE CODE:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data.OleDb; // put this here, and stop writing long namespaces inline
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Where possible, move code out of specific event handlers
// into methods which can be re-used from other client code.
// Here, I pulled the actual data access out into separate methods,
// and simply call it from the event handler:
this.LoadGridView(textBox1.Text);
}
private void LoadGridView(string UserID)
{
// Now we can load the gridview from other places in our
// code if needed:
this.dataGridView1.DataSource = this.MyUsers(UserID);
}
private DataTable MyUsers(string UserID)
{
var dt = new DataTable();
// Use a SQL Paramenter instead of concatenating criteria:
string SQL = "SELECT * FROM Leave WHERE userid = #UserID";
// The "using" statement limits the scope of the connection and command variables, and handles disposal
// of resources. Also note, the connection string is obtained from the project properties file:
using(OleDbConnection cn = new OleDbConnection(Properties.Settings.Default.MyConnectionString))
{
using (var cmd = new OleDbCommand(SQL, cn))
{
// For simpler things, you can use the "AddWithValue" method to initialize a new parameter,
// add it to the Parameters collection of the OleDBCommand object, and set the value:
cmd.Parameters.AddWithValue("#UserID", UserID);
// Get in, get out, get done:
cn.Open();
dt.Load(cmd.ExecuteReader());
cn.Close();
}
}
return dt;
}
}
}
Hope that helps. It's not how everyone might do it, but I have found it provides maximum flexibility, when you must work with MS Access.