C# Local SQL rows returned if statement - c#

I'm trying to get my login system to work. Currently I think I have everything in place for it to work except the if statement conditions (if row is returned, then if statement is true, else login unsuccessful). I'm not sure how to read in the number of rows returned, I did attempt to use the ExecuteReader Method but couldn't get it to work.
Appreciate any help, thanks.
Code:
private void btn_login_Click(object sender, EventArgs e)
{
SqlCeConnection connection = new SqlCeConnection(#"Data Source=C:\\temp\\Project\\WindowsFormsApplication2\\Database.sdf");
connection.Open();
SqlCeCommand command = new SqlCeCommand("SELECT * FROM Technician WHERE Name = '" + txt_username.Text + "' AND Password = '" + txt_password.Text + "' ");
SqlCeDataAdapter dataAdapter = new SqlCeDataAdapter(command);
if ()
{
MessageBox.Show("Login Successful");
System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(MainMenuForm));
t.Start();
this.Close();
}
else
{
MessageBox.Show("Login Unsuccessful");
return;
}
connection.Close();
}

I have changed your code to use a simpler ExecuteScalar that returns the first column of the first row obtained by your query
Of course, it is of extreme importance that you don't write your sql commands concatenating strings because this could fail in spectacular ways. (What if your textboxes contains a single quote and what if your user writes malicious text like this
using(SqlCeConnection connection = new SqlCeConnection(.....))
{
connection.Open();
string sqlText = "SELECT Count(*) FROM Technician WHERE Name = #name AND Password=#pwd"
SqlCeCommand command = new SqlCeCommand(sqlText, connection);
command.Parameters.AddWithValue("#name", txt_username.Text);
command.Parameters.AddWithValue("#pwd", txt_password.Text);
int result = (int)command.ExecuteScalar();
if (result > 0)
{
MessageBox.Show("Login Successful");
System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(MainMenuForm));
t.Start();
this.Close();
}
else
{
MessageBox.Show("Login Unsuccessful");
return;
}
}
Notice also the using statement, in your previous code you exit from the procedure if no login is found but you forget to close the connection. This could become a big problem during lifetime of your application. The Using statement prevents this
Now I should start talking about the weakness of storing and trasmitting passwords in clear text, but that is another matter

The method ExecuteNonQuery will return the number of rows affected.
int rowsAffected = command.ExecuteNonQuery();
bool userExists = rowsAffected > 0;
if (userExists) // The user exists
{
}
Note: However your application is vulnerable to SQL Injection. I.e. I could enter ;DROP TABLE Technician into the txt_password text box.
You should use a parameterized query instead or another authentication method which is more secure (ASP.NET membership for instance).
To use paramertised queries you can change the CommandText to:
SqlCeCommand command = new SqlCeCommand("SELECT * FROM Technician WHERE Name=#username AND password=#password";
And then add the parameters in via:
command.Parameters.AddWithValue("#username", txt_username.Text);
command.Parameters.AddWithValue("#password", txt_password.Text);
http://johnhforrest.com/2010/10/parameterized-sql-queries-in-c/

private void btn_login_Click(object sender, EventArgs e)
{
SqlConnection connection = new SqlConnection(#"Data Source=C:\\temp\\Project\\WindowsFormsApplication2\\Database.sdf");
connection.Open();
SqlCommand command = new SqlCommand("SELECT * FROM Technician WHERE Name = '" + txt_username.Text + "' AND Password = '" + txt_password.Text + "' ");
int row=command.ExecuteNonQuery();
if (row>0)
{
MessageBox.Show("Login Successful");
System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(MainMenuForm));
t.Start();
this.Close();
}
else
{
MessageBox.Show("Login Unsuccessful");
return;
}
connection.Close();
}

a=1;
b=1;
if a=b
{
a=c;
}
else
{
a=b;
}
else if
{
MessageBox.Show("Login Unsuccessful");
return i;

Related

ExecuteScalar return wrong value

Good day
I am working on login page where the user will be able to login and then change password after first login.Then, the user will be able to login to the system with the new password.
I found out that ExecuteScalar will help me to make the codes working perfectly. But, I am facing now that ExecuteScalar is returning wrong values where the user will be able to change the password but it will not allow him to redirect to the main page.
I have tried to change in if statement but still it showing me wrong results
SqlConnection con = new SqlConnection(#"Data Source=TOWELL\XPEDEON;User ID=xplive;Password=xplive");
try {
con.Open();
if (attemp < 3)
{
DataTable dt = new DataTable();
SqlCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = ("select count (*) from log_sup where ENTITY_DIVISION_CODE = '" + textBox1.Text + "'and DX_NUMBER = '" + textBox2.Text + "' ");
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(dt);
int result = Convert.ToInt32(cmd.ExecuteScalar());
if (result > 0)
{
Form3 F3 = new Form3();
F3.Show();
this.Hide();
}
else if(result == 0)
{
recby = textBox1.Text;
Form2 f2 = new Form2();
f2.Show();
this.Hide();
}
else
{
MessageBox.Show("WRONG PASSWORD, THIS IS YOUR " + attemp + " ATTEMPT ");
}
}
else if (attemp == 3)
{
MessageBox.Show("LOGIN EXCEED , PLEASE CONTACT THE ADMIN TO RESET YOUR ACCOUNT LOGIN");
textBox1.Enabled = false;
textBox2.Enabled = false;
label2.Enabled = false;
}
attemp++;
}
catch (Exception) {
}
con.Close();
the table query
where the user after changing the password, it will marks as 1 in order to check that the password has changed
I suggest changing the query:
Count(*) can be expensive (you may want to scan the entire table), when all you want is an answer for "if there any record such that..." - you can well stop early.
Let's parametrize the query (just imagine that I put "123'; delete from log_sup; --" into textBox1.Text)
Code:
...
cmd.CommandText =
#"select 1
from log_sup
where ENTITY_DIVISION_CODE = #prm_ENTITY_DIVISION_CODE
and DX_NUMBER = #prm_DX_NUMBER";
//TODO: cmd.Parameters.Add("param_name", RDMBS_TYPE) is a better choice
cmd.Parameters.AddWithValue("#prm_ENTITY_DIVISION_CODE", textBox1.Text);
cmd.Parameters.AddWithValue("#prm_DX_NUMBER", textBox2.Text);
using (var reader = cmd.ExecuteReader()) {
if (reader.Read()) { // We've succeeded in reading (at least) one record
Form3 F3 = new Form3();
F3.Show();
this.Hide();
}
else { // the cursor is empty
recby = textBox1.Text;
Form2 f2 = new Form2();
f2.Show();
this.Hide();
}
}
...

OleDbException was unhandled by user code in c#

Here is the cs file:
public int CheckExisting(String sqlDbQry, String sTable)
{
Qry = sqlDbQry;
con = new OleDbConnection(connectionstr);
if (con.State == ConnectionState.Open)
con.Close();
con.Open();
cmd = new OleDbCommand(Qry, con);
dr = cmd.ExecuteReader();
while (dr.Read())
rQry = Convert.ToInt32(dr[0].ToString());
con.Close();
return rQry;
}
Here is my another cs:
protected void btnsub_Click(object sender, EventArgs e)
{
if (objAdmin.CheckExisting("SELECT COUNT(*) FROM registration where Email='" + Textemail.Text.Trim() + "'", "Temp") > 0)
{
lblmail.Text = "Your EmailId already Registered, Please Login!";
return;
}
if (objAdmin.CheckExisting("SELECT COUNT(*) FROM registration where Phone_num='" + Textphone.Text.Trim() + "'", "Temp") > 0)
{
lblmail.Text = "Mobile number already exists, Please Login!";
return;
}
}
When i enter input details and hit submit, it shows error something like this,
Here is the error of Screenshot
Can anyone help me to fix this?
You are manually building a sql string from a textbox labeled "email". Email addresses usually contain an "#". Because you are building a raw sql query you are putting the "#" directly in to the query. OleDb interprets that as a SQL parameter, and expects you to supply it, which you are not, which is what is causing the error. You will get a similar error if any of your text boxes contain a ' (single quote).
You should look in to using OleDbCommand and OleDbParameter to pass in your parameters instead of sending raw strings. This will also fix your sql injection attack vulnerability that others have mentioned.
I can't edit your post so I'm doing it here.
public int CheckExisting(String sqlDbQry, String sTable)
{
try
{
Qry = sqlDbQry;
con = new OleDbConnection(connectionstr);
if (con.State == ConnectionState.Open)
con.Close();
con.Open();
cmd = new OleDbCommand(Qry, con);
dr = cmd.ExecuteReader();
while (dr.Read())
rQry = Convert.ToInt32(dr[0].ToString());
con.Close();
return rQry;
}
catch (OleDbException ex)
{
string message = ex;
//put your message on a texbox or alert handler error on the web
//or while debugging use a breakpoint on the exception handler
//use log
Console.WriteLine(message);
}
}
Keep in mind that with OleDb, parameters are positional, not named. You can name your parameters, but you cannot use the # syntax in your command (it throws an error about needing to declare a scalar variable) ... the correct syntax is to use the ? ... and it will take the parameters in the order in which you've added them.
Also, I prefer the .AddWithValue syntax, which is even more readable, I think.
protected void btnsub_Click(object sender, EventArgs e)
{
if (objAdmin.CheckExisting("SELECT COUNT(*) FROM registration where Email='" + this.Textemail.Text.Trim() + "'", "Temp") > 0)
{
lblmail.Text = "Your EmailId already Registered, Please Login!";
return;
}
if (objAdmin.CheckExisting("SELECT COUNT(*) FROM registration where Phone_num='" + this.Textphone.Text.Trim() + "'", "Temp") > 0)
{
lblmail.Text = "Mobile number already exists, Please Login!";
return;
}
}
Just put this.Textemail.Text and this.Textphone.Text , i hope so it will be helpful for you.

SQL Server database doesn't save the new queries until the application is closed

I have a problem with saving queries into my Local DB in the current session. However, the database got updated when I close the app.
Scenario: I have a login Window and Register Window, when user register I have queries to save his/her info into DB but after closing the whole application, it should save it in the same session without needing to close the app.
I'm using this code for registration window:
private async void button_Click(object sender, RoutedEventArgs e)
{
if (textBox.Text.Length >= 4 && textBox1.Password.Length >= 4)
{
using (var conn = new SqlConnection(#"Data Source"))
using (var cmd = conn.CreateCommand())
{
cmd.CommandText =
"Select Count(*) From Results Where PlayerName = #playerName";
conn.Open();
cmd.Parameters?.Add("#playerName", textBox.Text);
cmd.Parameters?.Add("#Password", textBox1.Password);
var count = (int) cmd.ExecuteScalar();
if (count == 0)
{
cmd.CommandText =
"INSERT INTO LoginInfo (PlayerName, Password) Values (#playerName , #Password)";
cmd.ExecuteNonQuery();
conn.Close();
Close();
}
else
{
label3.Content = "The UserName is already registerd!";
}
}
}
else
{
label3.Content =
"Please Enter Valid information User Name +" +
"and Password should be more than 4 Digits";
}
}
Edit: I used #displayName, suggestion and I saw that actually it updated because when I'm writing same info it gives that user already registered.
Probably there is a mistake with Linq to SQL in login window here is my login window code:
private void Login_Click(object sender, RoutedEventArgs e)
{
var db = new DataClasses1DataContext();
var userName = from t in db.LoginInfos
select new
{
t.Id,
t.PlayerName,
t.Password
};
foreach (var variable in userName)
{
if (UserName.Text == variable.PlayerName && text_Password.Password == variable.Password)
{
var openChoiceGame = new ChoiceGame(UserName.Text);
textBlock.Text = "The login information are correct ";
openChoiceGame.Show();
using (
var conn =
new SqlConnection(
#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\Saif-DevEnv\Source\Workspaces\QuizClashGame\GameQuizClash\Players.mdf;Integrated Security=True;Connect Timeout=30")
)
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "Select Count(*) From Results Where PlayerName = #playerName";
cmd.Parameters.Add("#playerName", UserName.Text);
conn.Open();
var count = (int) cmd.ExecuteScalar();
if (count == 0)
{
// It means it does not exist.
cmd.CommandText = "INSERT INTO Results(PlayerName) VALUES (#playerName)";
cmd.ExecuteNonQuery();
}
conn.Close();
var player = new SoundPlayer(#"C:\Users\Saif-DevEnv\Desktop\SoundRes\switch32.wav");
player.Play();
}
Close();
}
else
{
textBlock.Text = "The login information are not correct ";
}
}
}
Are there any errors with Login window code?
I don't see any reason for the async keyword. It should work fine after you remove that.
First thought: I see that you are ExecutingScalar() on Results while ExecutingNonQuery() on LoginInfo i.e. on two different tables. Is that the issue?
Second thought: You can change the way you are testing for inserting into LoginInfo. Do it this way rather -
if (cmd.ExecuteNonQuery() == -1)
{
label3.Content = "The UserName is already registerd!";
}
Maybe this helps: Asynchronous Programming
The problem was with Linq To Sql part.
However,the solution for it was I have added the source of data into DataContext(#DataSource) or in my code is DataClasses1DataContext(#DataSource);and also use Refresh Method db.Refresh(RefreshMode.OverwriteCurrentValues,_db.LoginInfos);

C# winform login using Ms Access 2013

I am creating a C# windows login form using MS Access 2013.
Login form using User ID(Autonumber) and Password(Short text).
My problem here is, it always crash(or Syntax error I guess) every time I click the LOGIN button and I can't trace the problem since I'm still inexperience in programming.
Table User
Fields: user_Id(Auto Number), password(short text), name(short text), type(number)
private void btn_Login_Click(object sender, EventArgs e)
{
try
{
if (string.IsNullOrEmpty(txt_UserId.Text))
{
lbl_warningUser.Visible = true;
lbl_warningUser.Text = "User ID is Empty";
}
if (string.IsNullOrEmpty(txt_Password.Text))
{
lbl_warningPass.Visible = true;
lbl_warningPass.Text = "Password is Empty";
}
if (txt_UserId.Text !="" & txt_Password.Text != "")
{
string constring = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Database/Health.accdb;";
string query = ("SELECT COUNT(*) FROM User WHERE user_Id = #ID AND password = #Pass");
using (OleDbConnection con = new OleDbConnection(constring))
using (OleDbCommand cmd = new OleDbCommand(query, con))
{
con.Open();
cmd.Parameters.AddWithValue("#ID", txt_UserId.Text);
cmd.Parameters.AddWithValue("#Pass", txt_Password.Text);
int result = (int)cmd.ExecuteScalar();
if (result > 0)
{
MessageBox.Show("Successfully Login");
con.Close();
this.Hide();
MainUI m = new MainUI();
m.Show();
}
else
{
MessageBox.Show("Incorrect User ID or Password");
}
con.Close();
}
}
}
catch (Exception ex)
{
MessageBox.Show(" "+ex);
}
}
User is a reserved word in MS Access I think, so you need to wrap it in square bracket delimiters. Also, you likely need to specify an alias for the COUNT function result:
"SELECT COUNT(*) AS qtyUsers FROM [User] WHERE user_Id = #ID AND password = #Pass"
txt_UserId.Text has a default return value of string, did you convert the value to an integer then try actually autonumber is integer.
First convert your value and try
Convert.ToInt32(txt_UserId.Text)

Why is my SQL Server CE code failing?

In my WindowsCE / Compact Framework (.NET1.1) project, I need to create a new table in code. I thought I could do it this way:
if (! TableExists("table42"))
{
CreateTable42();
}
public static bool TableExists(string tableName)
{
try
{
using (SqlCeConnection sqlConn = new SqlCeConnection(#"Data Source=\my documents\Platypus.SDF"))
{
sqlConn.Open();
string qryStr = "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ?";
SqlCeCommand cmd = new SqlCeCommand(qryStr, sqlConn);
cmd.Parameters[0].Value = tableName;
cmd.CommandType = CommandType.Text;
int retCount = (int)cmd.ExecuteScalar();
return retCount > 0;
}
}
catch (Exception ex)
{
MessageBox.Show("TableExists ex.Message == " + ex.Message);
MessageBox.Show("TableExists ex.ToString() == " + ex.ToString());
MessageBox.Show("TableExists ex.GetBaseException() == " + ex.GetBaseException());
return false;
}
}
...but the call to TableExists() fails; and shows me:
TableExists ex.Message ==
TableExists ex.ToString() == System.Data.SqlServerCe.SqlCeException at System.Data.SqlServerCe.SqlConnection.ProcessResults(Int32 hr) at ...at Open(boolean silent) ...
TableExists ex.GetBaseException() == [same as ex.ToString() above]
"Int32 hr" ... ??? What the Hec Ramsey is that?
As documented previously in these environs, I can't step through this projct, so I rely on those calls to MessageBox.Show().
The rest of the related code, if it may be of interest, is:
public static void CreateTable42()
{
try
{
using (SqlCeConnection con = new SqlCeConnection(#"Data Source=\my documents\Platypus.SDF"))
{
con.Open();
using (SqlCeCommand com = new SqlCeCommand(
"create table table42 (setting_id INT IDENTITY NOT NULL PRIMARY KEY, setting_name varchar(40) not null, setting_value(63) varchar not null)", con))
{
com.ExecuteNonQuery();
WriteSettingsVal("table42settingname","table42settingval");
}
}
}
catch (Exception ex)
{
MessageBox.Show("CreateTable42 " + ex.Message);
}
}
public static void WriteSettingsVal(string settingName, string settingVal)
{
using (SqlCeConnection sqlConn = new SqlCeConnection(#"Data Source=\my documents\Platypus.SDF"))
{
sqlConn.Open();
string dmlStr = "insert into tabld42 (setting_name, setting_value) values(?, ?)";
SqlCeCommand cmd = new SqlCeCommand(dmlStr, sqlConn);
cmd.CommandType = CommandType.Text;
cmd.Parameters[0].Value = settingName;
cmd.Parameters[1].Value = settingVal;
try
{
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show("WriteSettingsVal " + ex.Message);
}
}
}
UPDATE
Answer to Brad Rem's comment:
I don't think it's necessary to encase the param in quotes, as other working code is like:
cmd.Parameters.Add("#account_id", Dept.AccountID);
-and:
cmd.Parameters[0].Value = Dept.AccountID;
(it does it one way the first time when in a loop, and the other way thereafter (don't ask me why).
Anyway, just for grins, I did change the TableExists() parameter code from this:
cmd.Parameters[0].Value = tableName;
...to this:
cmd.Parameters.Add("#TABLE_NAME", tableName);
...but I still get the exact same result.
UPDATE 2
Here (http://msdn.microsoft.com/en-us/library/aa237891(v=SQL.80).aspx) I found this: "Caution You must specify the SQL Server CE provider string when you open a SQL Server CE database."
They give this example:
cn.ConnectionString = "Provider=Microsoft.SQLSERVER.OLEDB.CE.2.0; data source=\Northwind.sdf"
I'm not doing that; my conn str is:
using (SqlCeConnection sqlConn = new SqlCeConnection(#"Data Source=\my documents\CCRDB.SDF"))
Could that be my problem?
UPDATE 3
I took this gent's advice (http://www.codeproject.com/Answers/629613/Why-is-my-SQLServer-CE-code-failing?cmt=487657#answer1) and added a catch for SqlCeExcpetions so that it is now:
public static bool TableExists(string tableName)
{
try
{
using (SqlCeConnection sqlConn = new SqlCeConnection(#"Data Source=\my documents\CCRDB.SDF"))
{
sqlConn.Open();
string qryStr = "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = #TABLE_NAME";
SqlCeCommand cmd = new SqlCeCommand(qryStr, sqlConn);
cmd.Parameters.Add("#TABLE_NAME", tableName);
cmd.CommandType = CommandType.Text;
int retCount = (int)cmd.ExecuteScalar();
return retCount > 0;
}
}
catch (SqlCeException sqlceex)
{
MessageBox.Show("TableExists sqlceex.Message == " + sqlceex.Message);
MessageBox.Show("TableExists sqlceex.ToString() == " + sqlceex.ToString());
return false;
. . .
The SqlCeException message is: "There is a file sharing violation. A different process might be using the file [,,,,,]" then "...processresults ... open ... getinstance ..."
UPDATE 4
Trying to use ctacke's sample code, but: Is Transaction absolutely necessary? I had to change the code to the following for my scenario/milieu, and don't know what Transaction should be or how to build it:
public static bool TableExists(string tableName)
{
string sql = string.Format("SELECT COUNT(*) FROM information_schema.tables WHERE table_name = '{0}'", tableName);
try
{
using (SqlCeConnection sqlConn = new SqlCeConnection(#"Data Source=\my documents\HHSDB.SDF"))
{
SqlCeCommand command = new SqlCeCommand(sql, sqlConn);
//command.Transaction = CurrentTransaction as SqlCeTransaction;
command.Connection = sqlConn;
command.CommandText = sql;
int count = Convert.ToInt32(command.ExecuteScalar());
return (count > 0);
}
}
catch (SqlCeException sqlceex)
{
MessageBox.Show("TableExists sqlceex.Message == " + sqlceex.Message);
return false;
}
}
UPDATE 5
With this code, the err msg I get is, "An err msg is available for this exception but cannot be displayed because these messages are optional and are not currently insallted on this device. Please install ... NETCFv35.Messages.EN.cab"
UPDATE 6
All too typically, this legacy, ancient-technology project is giving me headaches. It seems that only one connection is allowed to be open at a time, and the app opens one from the outset; so, I have to use that connection. However, it is a DBConnection, not a SqlCeConnection, so I can't use this code:
using (SqlCeCommand com = new SqlCeCommand(
"create table hhs_settings (setting_id int identity (1,1) Primary key, setting_name varchar(40) not null, setting_value(63) varchar not null)", frmCentral.dbconn))
{
com.ExecuteNonQuery();
WriteSettingsVal("beltprinter", "ZebraQL220");
}
...because the already-open connection type passed as an arg to the SqlCeCommand constructor is DBCommand, not the expected/required SqlCeConneection.
The tentacles of this code are far too wide and entrenched to rip out by the roots and refactor to make it more sensible: a single tentative step in the foothills causes a raging avalanche on Everest.
For fun I'd try two things. First, replace the '?' parameter with a named parameter like '#tablename' and see if that changes things. Yes, I know '?' should work, but it's a confusing, ugly precedent and maybe since it's a system table it's wonky. Yes, it's a stretch, but worth a try just to know.
The second thing I'd do is something like this method from the SQLCE implementation of the OpenNETCF ORM:
public override bool TableExists(string tableName)
{
var connection = GetConnection(true);
try
{
using (var command = GetNewCommandObject())
{
command.Transaction = CurrentTransaction as SqlCeTransaction;
command.Connection = connection;
var sql = string.Format("SELECT COUNT(*) FROM information_schema.tables WHERE table_name = '{0}'", tableName);
command.CommandText = sql;
var count = Convert.ToInt32(command.ExecuteScalar());
return (count > 0);
}
}
finally
{
DoneWithConnection(connection, true);
}
}
Note that I didn't even bother parameterizing, largely because I doubt it will provide any perf benefit (queue the hordes whining about SQL injection). This way definitely works - we've got it deployed and in use in many live solutions.
EDIT
For completeness (though I'm not sure it adds to clarity).
protected virtual IDbConnection GetConnection(bool maintenance)
{
switch (ConnectionBehavior)
{
case ConnectionBehavior.AlwaysNew:
var connection = GetNewConnectionObject();
connection.Open();
return connection;
case ConnectionBehavior.HoldMaintenance:
if (m_connection == null)
{
m_connection = GetNewConnectionObject();
m_connection.Open();
}
if (maintenance) return m_connection;
var connection2 = GetNewConnectionObject();
connection2.Open();
return connection2;
case ConnectionBehavior.Persistent:
if (m_connection == null)
{
m_connection = GetNewConnectionObject();
m_connection.Open();
}
return m_connection;
default:
throw new NotSupportedException();
}
}
protected virtual void DoneWithConnection(IDbConnection connection, bool maintenance)
{
switch (ConnectionBehavior)
{
case ConnectionBehavior.AlwaysNew:
connection.Close();
connection.Dispose();
break;
case ConnectionBehavior.HoldMaintenance:
if (maintenance) return;
connection.Close();
connection.Dispose();
break;
case ConnectionBehavior.Persistent:
return;
default:
throw new NotSupportedException();
}
}
wow... still struggling... I did too when I first got started on a handheld device SQL-CE. My current project is running with C#.Net 3.5 but I think the principles you are running into are the same. Here is what is working for my system in it's close parallels to yours.
First, the connection string to the handheld. It is just
string myConnString = #"Data Source=\MyFolder\MyData.sdf";
no reference to the sql driver
Next, the TableExists
SqlCeCommand oCmd = new SqlCeCommand( "select * from INFORMATION_SCHEME.TABLES "
+ " where TABLE_NAME = #pTableName" );
oCmd.Parameters.Add( new SqlCeParameter( "pTableName", YourTableParameterToFunction ));
The "#pTableName" is to differentiate between the "TABLE_NAME" column and to absolutely prevent any issues about ambiguity. The Parameter does NOT get the extra "#". In SQL, the # indicates to look for a variable... The SqlCeParameter of "pTableName" must match as it is in the SQL Command (but without the leading "#").
Instead of issuing a call to ExecuteScalar, I am actually pulling the data down into a DataTable via
DataTable oTmpTbl = new DataTable();
SqlCeDataAdapter da = new SqlCeDataAdapter( oCmd );
da.Fill( oTmpTbl );
bool tblExists = oTbl.Rows.Count > 0;
This way, I either get records back or I dont... if I do, the number of records should be > 0. Since I'm not doing a "LIKE", it should only return the one in question.
When you get into your insert, updates and deletes, I have always tried to prefix my parameters with something like "#pWhateverColumn" and make sure the SqlCeParameter is by the same name but without the "#". I haven't had any issues and this project has been running for years. Yes it's a .net 3.5 app, but the fundamental basics of connecting and querying SHOULD be the same.
If it IS all within your application, I would try something like creating a single global static "Connection" object. Then, a single static method to handle it. Then, instead of doing a NEW connection during every "using" attempt, change it to something like...
public static class ConnectionHandler
{
static SqlCeConnection myGlobalConnection;
public static SqlCeConnection GetConnection()
{
if( myGlobalConnection == null )
myGlobalConnection = new SqlCeConnection();
return myGlobalConnection;
}
public static bool SqlConnect()
{
GetConnection(); // just to ensure object is created
if( myGlobalConnection.State != System.Data.ConnectionState.Open)
{
try
{
myGlobalConnection.ConnectionString = #"Data Source=\MyFolder\MyDatabase.sdf";
myGlobalConnection.Open();
}
catch( Exception ex)
{
// optionally messagebox, or preserve the connection error to the user
}
}
if( myGlobalConnection.State != System.Data.ConnectionState.Open )
MessageBox.Show( "notify user");
// return if it IS successful at opening the connection (or was already open)
return myGlobalConnection.State == System.Data.ConnectionState.Open;
}
public static void SqlDisconnect()
{
if (myGlobalConnection!= null)
{
if (myGlobalConnection.State == ConnectionState.Open)
myGlobalConnection.Close();
// In case some "other" state, always try to force CLOSE
// such as Connecting, Broken, Fetching, etc...
try
{ myGlobalConnection.Close(); }
catch
{ // notify user if issue}
}
}
}
... in your other class / function...
if( ConnectionHandler.SqlConnect() )
Using( SqlCeConnection conn = ConnectionHandler.GetConnection )
{
// do your stuff
}
... finally, when your app is finished, or any other time you need to...
ConnectionHandler.SqlDisconnect();
This keeps things centralized, and you don't have to worry about open/close, what the connection string is buried all over the place, etc... If you can't connect, you can't run a query, don't try to run the query if it can't even get that far.
I think it may be a permission issue on INFORMATION_SCHEMA system views. Try the following.
GRANT VIEW DEFINITION TO your_user;
See here for more details

Categories

Resources