Simple SQL Insert - c#

I'm new to databases and am trying to add a new record using SQL. The code runs fine the first time, but the second time throws an error saying that it can't write duplicates to a unique key. The third time runs fine, but the fourth time throws the error. Basically, it seems that every other time, the error is thrown. I understand why the error would be thrown if data was written, but when I examine the database, it remains empty. What am I doing wrong in my code that is causing the query to not bother writing the data?
EDIT If I enter the SQL directly within the database, it works. It doesn't work when I use the C# code below.
using (SqlCeConnection con = new SqlCeConnection(conString))
{
con.Open();
using (SqlCeCommand com = new SqlCeCommand("INSERT INTO User (Name, Age, URL) VALUES ( #name, #age, #url )", con))
{
com.Parameters.AddWithValue("#name", "James Y");
com.Parameters.AddWithValue("#age", 28);
com.Parameters.AddWithValue("#url", "www.example.com" );
com.ExecuteNonQuery();
}
}

I've partially figured it out. Apparently you have to also download SQL CE Tools for Visual Studio. I did this and I had a new option to include SQL CE 4 into my project (I was using the SQLCE option, assuming that it would use 4.0 by default since that's the one I installed). Only problem now is that when I try and add it, it says that it's not supported by the project type (Console project). I saw a post on MSDN that said that SQLCE 4 was for web-only projects but it was a post from a few months back and the current download page says it's for web or desktop applications. Either way, this is proving to be too much of a hassle to bother with and so I'm just going to look for an alternate database if I can't resolve this soon.
FIXED I uninstalled SQLCE4 and the SQLCE Tools, then reinstalled them.

Try and do the following as your SQL:
INSERT INTO [User] (Name, Age, URL) VALUES ( #name, #age, #url )
User is a reserved word in sql server. You should try not to name your table as "user".

Name is a reserved word. Wrap it in []
using (SqlCeCommand com = new SqlCeCommand("INSERT INTO User ([Name], Age, URL) VALUES ( #name, #age, #url )", con))

Since you use DataDirectory in your connection string, the file is copied to your bin/debug folder, so you have several copies of the database, one in your project and one in your debug folder. Make the connection string a full path to avoid any confusion while debugging!

Related

SQL Server Express database table not updating

I wonder why my SQL Server Express database table doesn't get updated when the method below executes successfully?
public void addUser(User user)
{
string query = "INSERT INTO users (username, password, firstname, lastname, isactive, accesslevel) VALUES (#usr, #psw, #fname, #lname, #status, #access)";
pSqlConn = new SqlConnection(pConnectingString);
SqlCommand cmd = new SqlCommand(query, pSqlConn);
SqlParameter pmtrUsername = new SqlParameter("#usr", user.Username);
SqlParameter pmtrPassword = new SqlParameter("#psw", user.Password);
SqlParameter pmtrFirstname = new SqlParameter("#fname", user.Firstname);
SqlParameter pmtrLastname = new SqlParameter("#lname", user.Lastname);
SqlParameter pmtrStatus = new SqlParameter("#status", user.IsActive);
SqlParameter pmtrAccessLevel = new SqlParameter("#access", user.AccessLevel);
cmd.Parameters.Add(pmtrFirstname);
cmd.Parameters.Add(pmtrLastname);
cmd.Parameters.Add(pmtrUsername);
cmd.Parameters.Add(pmtrPassword);
cmd.Parameters.Add(pmtrStatus);
cmd.Parameters.Add(pmtrAccessLevel);
pSqlConn.Open();
cmd.ExecuteNonQuery();
System.Windows.Forms.MessageBox.Show("Success!");
pSqlConn.Close();
}
The whole User Instance and AttachDbFileName= approach is flawed - at best! When running your app in Visual Studio, it will be copying around the .mdf file (from your App_Data directory to the output directory - typically .\bin\debug - where you app runs) and most likely, your INSERT works just fine - but you're just looking at the wrong .mdf file in the end!
If you want to stick with this approach, then try putting a breakpoint on the myConnection.Close() call - and then inspect the .mdf file with SQL Server Mgmt Studio - I'm almost certain your data is there.
The real solution in my opinion would be to
install SQL Server Express (and you've already done that anyway)
install SQL Server Management Studio Express
create your database in SSMS Express, give it a logical name (e.g. StoreManagerDB)
connect to it using its logical database name (given when you create it on the server) - and don't mess around with physical database files and user instances. In that case, your connection string would be something like:
Data Source=.\\SQLEXPRESS;Database=StoreManagerDB;Integrated Security=True
and everything else is exactly the same as before...
Also see Aaron Bertrand's excellent blog post Bad habits to kick: using AttachDbFileName for more background info.
Make sure the database connection variable is the right syntax and i advise you include an error syntax to show when the db is not connected

.NET Dapper/MySql 8.0 issue: Only root user is able to execute stored procedure. Other users get SqlNullValueException [duplicate]

I am trying to setup my .NET 4.7.1 program that is connecting to a MySQL database 8.0 to use the minimum privileges to run.
The .NET program is using MySql.Data to make connection. The minimum right for a user to execute a stored procedure is typically only EXECUTE privilege. This works fine from MySQL workbench or command line.
Upon running the .NET program this does return the following exception:
System.Data.SqlTypes.SqlNullValueException: 'Data is Null. This method or property cannot be called on Null values.'
To make it easy, I have create a very small demo program to demonstrate the issue.
Setup of the database:
CREATE DATABASE Spike;
CREATE PROCEDURE TestAccess()
BEGIN
END;
CREATE USER Spike#localhost IDENTIFIED WITH mysql_native_password BY 'sample';
GRANT EXECUTE ON PROCEDURE `TestAccess` TO Spike#localhost;
Setup program code:
static void Main(string[] args)
{
using (MySqlConnection conn = new MySqlConnection("Server=localhost;Database=Spike;uid=Spike;pwd=sample"))
{
conn.Open();
Console.WriteLine("Connection open");
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = conn;
cmd.CommandText = "TestAccess";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
Console.WriteLine("Query executed");
}
Console.ReadKey();
}
The crash happens at the line cmd.ExecuteNonQuery();
The stack from the crash is interesting, since it seems to indicate that the information_schema is queried. When logging all statements I can see that the last statement before the exception is:
SELECT * FROM information_schema.routines WHERE 1=1 AND routine_schema LIKE 'Spike' AND routine_name LIKE 'TestAccess'
I cannot grant different rights on information_schema, but I could give more rights on the stored procedure to make more information visible in the routines table, this feels wrong however. Simple tests with granting CREATE and ALTER access also did not work.
Is there something else I can do, without granting too much privileges?
This appears to be a bug in Connector/NET, similar to bug 75301 but a little different. When it's trying to determine parameter metadata for the procedure, it first creates a MySqlSchemaCollection named Procedures with all metadata about the procedure. (This is the SELECT * FROM information_schema.routines WHERE 1=1 AND routine_schema LIKE 'Spike' AND routine_name LIKE 'TestAccess' query you see in your log.)
The Spike user account doesn't have permission to read the ROUTINE_DEFINITION column, so it is NULL. Connector/NET expects this field to be non-NULL and throws a SqlNullValueException exception trying to read it.
There are two workarounds:
1) The first, which you've discovered, is to set CheckParameters=False in your connection string. This will disable retrieval of stored procedure metadata (avoiding the crash), but may lead to harder-to-debug problems calling other stored procedures if you don't get the order and type of parameters exactly right. (Connector/NET can no longer map them for you using the metadata.)
2) Switch to a different ADO.NET MySQL library that doesn't have this bug: MySqlConnector on NuGet. It's highly compatible with Connector/NET, performs faster, and fixes a lot of known issues.
I found an answer with which I am quite pleased. It is changing the connection string by adding CheckParameters=false:
using (MySqlConnection conn = new MySqlConnection("Server=localhost;Database=Spike;uid=Spike;pwd=sample;CheckParameters=false"))
This disables parameter checking, and thereby information_schema queries.

How to check if my SQL Server Express database exceeds the 10 GB size limit?

I am developing a web site, it uses SQL Server 2008 R2 Express for its database. And in testing, there is a lot of data and images stored into this database.
According to wiki, the SQL Server Express edition has a 10 GB size limit. When I insert data and reach the limit, what exception will be thrown? Or, how do I detect the approaching limit problem by codes ?
I use EF 5 with code-first approach to insert large data set.
In tests I have seen that:
sp_spaceused
won't work as expected, it showed 12GB after deleting lots of records. And the other answers regarding query sys.databases were not clear enough to me.
Searching around I found a very good explanation regarding SQL Server 2012 Express Edition 10GB Size Limit on Ramons weblog [EDIT2018 updated link]
SELECT
[name] AS [Filename],
[size]/128.0 AS [Filesize],
CAST(FILEPROPERTY([name],'SpaceUsed') AS int)/128.0 AS [UsedSpaceInMB],
[size]/128.0 - CAST(FILEPROPERTY([name],'SpaceUsed') AS int)/128.0 AS [AvailableSpaceInMB],
[physical_name] AS [Path]
FROM sys.database_files
"... space includes the transaction log and it also includes all unused space within these files. .... SQL Server Express will start complaining when it cannot reserve any more space for the datafile."
So checking
CAST(FILEPROPERTY([name],'SpaceUsed') AS int)/128.0 AS [UsedSpaceInMB]
seems to be the best option.
In combination with EF in c# my request to the DB looks like
string sqlSelect = "SELECT CAST(FILEPROPERTY([name],'SpaceUsed') AS int)/128.0 AS [UsedSpaceInMB] FROM sys.database_files";
var dbResult = dbInstance.Database.SqlQuery<Decimal>(sqlSelect).FirstOrDefault();
double spaceUsedInGb = Convert.ToDouble(dbResult)/1024;
Execute this SQL command, and it will reveal the disk-space usage of current database.
sp_spaceused
It also can be used to query the space usage of specific table. This link provides useful information about this problem.
To check the database size query:
sys.databases
Just query this, perhaps with C# or if you use SSMS (sql server management studio) shell, you can schedule a job that emails you or whatever you want.
Example:
SQL Server 2008: How to query all databases sizes?
Edit: NOT sure if error is thrown, it should log to event log or a sql log...
Side note:
Developer version is only $50 and holds same as Datacenter which hold 524 PB
http://technet.microsoft.com/en-us/library/cc645993%28v=sql.105%29.aspx
To Check the Size of the Database Two Ways:
/* new school way - data plus log and run in the local db that you want to see
here you can see the log and the mdf file.
*/
SELECT size*8.0/1024.0 as size_in_gb, *
FROM sys.database_files
GO
/* old school way, run for all db size*/
sp_helpdb
FYI - the MDF and NDF files are the only ones that attribute to the file size exceeding 10GB.
I am using the following method to calculate database current size crucial for comparing with sql size limitations:
public static int GetDbSizeInMB([NotNull] string connectionString) {
using (SqlConnection sqlConnection = new SqlConnection(connectionString)) {
sqlConnection.Open();
using (var sqlCommand = new SqlCommand()) {
sqlCommand.CommandType = CommandType.Text;
sqlCommand.CommandText = #"
SELECT SUM(CAST(FILEPROPERTY([name],'SpaceUsed') AS int)/128.0) AS [UsedSpaceInMB]
FROM sys.database_files
WHERE type_desc like 'ROWS' or type_desc like 'FULLTEXT'
";
sqlCommand.Connection = sqlConnection;
return Convert.ToInt32(sqlCommand.ExecuteScalar());
}
}
)

INSERT INTO command not working

Before I start, I'll let you know that I tried everything that has already been suggested on previous questions and other websites before I considered posting a question myself. As it happens, nothing seems to work and I'm just about fed up with this.
As some background information, this is for my Computing A2 project, so I'm kind of stuck for time now - i.e. I can't be changing loads of my code ideally.
Anyway, onto the issue...
I'm using SQLCe in my code to read from various tables and write to one. So far, the code for reading from the tables works fine, so that's any connection issues out the way first. The piece of code I am struggling with is as follows:
string connectionString = Properties.Settings.Default.BookingSystemDatabaseConnectionString;
using (SqlCeConnection myConnection = new SqlCeConnection(connectionString))
{
myConnection.Open();
try
{
string commandStr = "INSERT INTO bookings(username, room, time) VALUES(#username, #room, #time)";
SqlCeCommand myCommand = new SqlCeCommand(commandStr);
//Passes parameters into SQL command.
myCommand.Parameters.AddWithValue("username", StaticUser.StudentUser.username);
myCommand.Parameters.AddWithValue("room", roomBox.Text);
myCommand.Parameters.AddWithValue("time", timeBox.Text);
//Executes SQL command. Returns the number of affected rows (unecessary for my purposes; a bi-product if you will).
myCommand.ExecuteNonQuery();
}
catch
{
System.Windows.Forms.MessageBox.Show("Could not write new booking to database. This is likely because the database cannot be reached.", "Error");
Program.AccessError = true;
}
myConnection.Close();
}
This is just one of the many ways I have tried to combat the issue I am having. I have also explored:
myCommand.Parameters.Add(new SqlCeParameter("username", StaticUser.StudentUser.username));
to pass the parameters...and another method which escapes me now (using ".Value = StaticUser.StudentUser.username" I think). Furthermore, I have tried using a 'using' statement for the command to save me closing the connection myself (I will probably end up using a solution that uses 'using'). Finally (albeit this isn't a chronological recollection), I tried:
SqlCeCommand myCommand = new SqlCeCommand("INSERT INTO bookings(username, room, time) VALUES(#username, #room, #time)", myConnection)
Again, of course, to no avail.
To highlight the actual symptoms of the issue I am having: The code appears to run fine; stepping through the full method I have pasted above shows that no error is being caught (of course, the message box does not appear - I realised afterwards that stepping through was arguably an unnecessary procedure) and in the other methods I have touched on, the same thing happens. The issue, then, is that the table 'bookings' is not actually being updated.
So, my question, why?
I didn't do the obvious and check the Debug folder for an updated database.
Look for a copy of the database file in your bin/debug folder.
Use full path in connection string, and preferably do not include the sdf file in your project (or at least set build action to None)
i think you are not defining a connection for the command
try
mycommand.connection = connectiostring;

error in stored procedure Access

I have created a query which is: SELECT Replace(column_name,a,b) AS expr1
FROM table1; the name of this query is:filepath.
I have wrote the following code in C#. when i compile the code it Syntax error in PROCEDURE clause.
OleDbCommand cmd1 = new OleDbCommand();
cmd1.Connection= ren_connection1;
cmd1.CommandType = CommandType.Text;
cmd1.CommandText = "Execute filepath";
OleDbParameter oldfilevalue = new OleDbParameter();
oldfilevalue.ParameterName = "a";
oldfilevalue.OleDbType = OleDbType.VarChar;
oldfilevalue.Direction = ParameterDirection.Input;
oldfilevalue.Value = oldname2;
OleDbParameter newfilevalue = new OleDbParameter();
newfilevalue.ParameterName = "b";
newfilevalue.OleDbType = OleDbType.VarChar;
newfilevalue.Direction = ParameterDirection.Input;
newfilevalue.Value = oldname1;
cmd1.Parameters.Add(oldfilevalue);
cmd1.Parameters.Add(newfilevalue);
i = cmd1.ExecuteNonQuery();
//oldefile value can be like this: D:/myfile/pictures/cars/
//newfile value can be like this: D:/myfile/pictures/jeeps/
i want to replace in a row a string with another string without modifying the whole row..and i thought replace will work but it didnt :(
access version is:2007.
any idea or help will be greatly appreciated.
Thanks alot.
I am afraid Replace is only available if you are running within Access, as Vincent mentions, it is a VBA function, not a Jet/ACE function. Also discussed: Exception when trying to execute "REPLACE" against MS Access. I have replied to what i think is your first question, update table access, with a possible solution.
Try changing your commandtext with
cmd1.CommandText = "EXECUTE yourProcedureName";
Edit now that your procedure is invoked correctly you need to work around the missing "Replace" function (btw, have you tried Vincent Vancalbergh's suggestion to see if "Replace can be made to work? That would be much easier....)
What I was saying in the comments is that you could select the content of the table, perform the replace in c# code and (if needed) update your table with the new values.
your select becomes:
SELECT table1_id, column_name FROM table1;
and your code changes like this:
//you should change ExecuteNonQuery to ExecuteReader, since you want
// to read the results of your SELECT
OleDbDataReader rdr= cmd1.ExecuteReader();
//Iterate through the table
while(rdr.Read())
{
string currentValue=rdr["column_name"].ToString();
string newValue = currentValue.Replace(a, b);
//now do what you need with the row
// ...
}
I found the following here:
Prior to a company wide upgrade to XP
there was no problem with access
databases, so I am not sure if this
would be a solution to your issue. But
I had a problem similar to yours after
an upgrade to XP from 2000 with some
access databases. Undefined Function
"Replace" errors started to pop up. At
the end of the day it turned out to be
the version of VBA installed. 6.0
versus 6.3. The problem machines had
6.0 installed. Start access Help -> About MS Access -> SYSTEM INFO ->
APPLICATIONS -> Microsoft Access 2000
-> SUMMARY. The VBA version of 6.00 produced the error, VBA version 6.03
no problem. Take Care, Nick
Now the question is, what VBA version are you using?
The solution is in #onedaywhen's answer her:
Exception when trying to execute "REPLACE" against MS Access
It uses Mid(), Len() and InStr() in place of Replace().

Categories

Resources