'Microsoft.Data.Sqlite' unexpected behaviour - c#

There is a method in my code, which initializes sqlite3 db to a specified directory as you can see in the following code snippet:
using System;
using System.IO;
using Microsoft.Data.Sqlite;
namespace test
{
public static class DatabaseUtils
{
public static void InitializeDatabase(string directoryPath)
{
if (!Directory.Exists(directoryPath))
{
throw new Exception();
}
string sqliteFile = Path.Combine(Path.GetFullPath(directoryPath), "test.sqlite3");
if (File.Exists(sqliteFile))
{
throw new Exception();
}
else
{
try
{
File.Create(sqliteFile).Dispose();
using (SqliteConnection connection = new SqliteConnection($"Data Source={sqliteFile};Mode=ReadWrite"))
{
connection.Open();
using (SqliteCommand command = new SqliteCommand())
{
command.Connection = connection;
command.CommandText = "DROP TABLE IF EXISTS MyTable; CREATE TABLE MyTable (Primary_Key INTEGER PRIMARY KEY, Text_Entry NVARCHAR(2048) NULL)";
command.ExecuteNonQuery();
}
connection.Close();
}
}
catch (Exception)
{
throw;
}
}
}
}
}
Case 1:
When calling this this method for the first time, everything works as expected.
Which means => Database file is created with table(MyTable) that is specified in the code.
Case 2:
When calling this this method for the 2nd time, after manual database file deletion,
database file is created WITHOUT table(MyTable) that is specified in the code and the following error occurs => SQLite Error 8: 'attempt to write a readonly database'
It seems to me, as if connection to the database was not properly disposed after first run or database that was created during first run, stays cached in memory somehow.
Expected behaviour:
Method should create sqlite database file with specified tables, every time it's called, when the conditions above are met.
Used packages:
"Microsoft.Data.Sqlite, Version 6.0.2",
"PowerShellStandard.Library, Version 5.1.0"
Target framework:
.NET 6
Worth to mention:
When replacing 'File.Create()' method with 'Mode=ReadWriteCreate' ConnectionString, the file doesn't get created for the 2nd time, after manual deletion. Only during the first method run.
EDIT:
Swapped 'Microsoft.Data.Sqlite' for 'System.Data.SQLite.Core'
and now the method works as expected every time.
I guess It's either a BUG in 'Microsoft.Data.Sqlite', or I am just missing an important difference between those 2 libraries.
Would be great to have an official answer from MSFT devs as to what I was doing wrong.

After some deep digging in github, I have found an actual answer to my original question. There's a feature called 'connection pooling', which caused this 'Unexpected behaviour' that I have described in my question.
To DISABLE this feature, either add 'Pooling=False' to ConnectionString, or call 'SqliteConnection.ClearAllPools()' at the point where you want the connection to be disposed (using statement is not sufficient).

there might be a problem on opening and closing the connection 2 times:
Could you try it like this:
using (SQLiteConnection connection = new SQLiteConnection($"Data Source={SqliteFile};Mode=ReadWrite"))
{
using (SQLiteCommand command = new SQLiteCommand())
{
command.Connection = connection;
command.CommandText = "DROP TABLE IF EXISTS MyTable; CREATE TABLE MyTable (Primary_Key INTEGER PRIMARY KEY, Text_Entry NVARCHAR(2048) NULL)";
command.ExecuteNonQuery();
}
}

Ah ok, I missed one part. For me it always works like this (in short):
private SQLiteConnection OpenDataBase(string dataBasePath)
{
SQLiteConnection connection = new SQLiteConnection($#"Data Source = {dataBasePath}; Version = 3; New = True; Compress = True; ");
connection.Open();
return connection;
}
public void CreateTable(string dataBasePath)
{
using (SQLiteConnection? connection = OpenDataBase(dataBasePath))
{
string create = "DROP TABLE IF EXISTS MyTable; CREATE TABLE MyTable (Primary_Key INTEGER PRIMARY KEY, Text_Entry NVARCHAR(2048) NULL)"; ;
using (SQLiteCommand command = new SQLiteCommand(create, connection))
{
command.ExecuteNonQuery();
}
}
}

Related

The application freezes when I try to update timestamp column with a placeholder in an Oracle database using C#

I am trying to update 2 columns in an Oracle database using C#. The columns I want to update are StartTime i.e. a timestamp and Name i.e. string. However when I run my code, the application freezes. I following is my code:
public int StartProduction(string serialNr, string empName)
{
string queryString = "UPDATE RO_EXEMPLAAR_PIM SET PLAKTAFEL_START=systimestamp, STARTED_BY=:startedBy WHERE SERIENR=:serialNr";
using (OracleConnection connection = new OracleConnection(connectionString))
{
using (OracleCommand command = new OracleCommand(queryString, connection))
{
try
{
OracleDataAdapter da = new OracleDataAdapter();
connection.Open();
command.Parameters.AddWithValue("serialNr", serialNr);
command.Parameters.AddWithValue("startedBy", empName);
da.InsertCommand = command;
int nrOfRecordsChanged = command.ExecuteNonQuery();
return nrOfRecordsChanged;
}
catch
{
return -1; //which means the try-block was not executed succesfully
}
finally
{
connection.Close();
}
}
}
}
I call it in a form as this:
if (dh.StartProduction(serialNr, empName) != -1)
{
MessageBox.Show("Production started successfully!");
}
else
{
MessageBox.Show("Production cannot be started!");
}
I looked up online and could not find what is wrong with my code. Thanks in advance!
Try a non locking read query like;
SELECT * FROM V$VERSION;
If that works (proving your connection string works).
Then you probably have a locking issue.
In general: (especially for devs)
Make sure you are not missing a "commit;" in your sql-developer or dbvisualizer or something like that. (or somebody on your dev team).
Running an update without a "commit;" in side these tools will lock a row.
If you can't find the culprit : a reboot of the server is in order.

MySQL insert C# fails when Connection Pooling is activated

I have the following INSERT method in a C# web project. If I run the project without MySQL connection poling everything works fine, but when I activate Pooling=True in the DB connection string this method stops working, the insert statements never complete.
I realized how to modify the code to make it work, but I would like to understand what is happening and I hope you could help.
When I comment line //myR.Close(); everything works fine.
using MySql.Data.MySqlClient;
//query example consulta="INSERT INTO users (id, name) VALUES (1, 'Rob');
public static MySqlConnection GetWriteConnection()
{
string connStr = MySqlConnectionStrings.WriteConnectionString;
MySqlConnection conn = new MySqlConnection(connStr);
return conn;
}
public static MySqlConnection GetReadConnection()
{
string connStr = MySqlConnectionStrings.ReadConnectionString;
MySqlConnection conn = new MySqlConnection(connStr);
return conn;
}
public static bool Insert(string consulta)
{
MySqlConnection conn = BdaHelper.GetWriteConnection();
conn.Open();
using (conn)
{
try
{
if (conn.State == ConnectionState.Closed)
{
conn.Open();
}
MySqlCommand micomando = new MySqlCommand(consulta, conn);
micomando.ExecuteNonQuery(); //still not working
return true;
}
catch (Exception ex)
{
return false;
}
}
}
My app has also multi-thread concurrency and two types of database connections, one specifically for only-read purposes and other different for write. When an insert statement fails I don't get any error simply the change doesn't commit in the database. Reading the article in the comments I don't think this applies to this issue but I would add an example of my main program:
MySqlConnection readConnection = BdaHelper.GetReadConnection();
using (readConnection)
{
var users = GetUsers(readConnection);
var credentials = GetCredentials(readConnection);
//Example is the query that fails don't giving any exception
Insert("INSERT INTO login_log (id_user, date) VALUES (1, now())");
}
May the problem be caused because there are two concurrent connections?
I shouldn't reuse read connection, even is a different connection than the write connection?

c# odbc update query doesnt work properly

Hi I'm having a lot of truble doing a program in c#
i have to connect to SQLANYWHERE 11 and do an update to a table
could u tell me where I'm wrong?
program go well until i reach the:
int number = wCommand.ExecuteNonQuery(); line
the program doesnt crash but tables get not updated
string dns = "Dsn=dattest;Uid=******;Pwd=******;";
OdbcDataReader reader;
OdbcCommand wCommand;
ODBCClass dst1 = new ODBCClass(dns);
queryins = "UPDATE dba.Sala_export_dati_macchina_produzione SET stato='p'";
// +"WHERE id_prd_lav_ord_lav='"+ id_prd_lav_ord_lav + "'";
wCommand = dst1.GetCommand(queryins);
int number = wCommand.ExecuteNonQuery();
Console.WriteLine("executed "+ number);
this is the odbc class that i'm using
public class ODBCClass
{
OdbcConnection oConnection;
OdbcCommand oCommand;
public ODBCClass(string DataSourceName)
{
oConnection = new OdbcConnection(DataSourceName);
try
{
oConnection.Open();
System.Diagnostics.Trace.WriteLine("Connessione stabilita con il database " + DataSourceName);
}
catch (OdbcException caught)
{
System.Diagnostics.Trace.WriteLine(caught.Message);
}
}
public void CloseConnection()
{
oConnection.Close();
}
public OdbcCommand GetCommand(string Query)
{
oCommand = new OdbcCommand
{
Connection = oConnection,
CommandText = Query
};
return oCommand;
}
public void Dispose()
{
oConnection.Close();
}
}
EDIT
just in case i've tried to change connection string with this pattern:
#"Driver={SQL Anywhere 11};DatabaseName=my_db_name;EngineName=my_server_name;uid=username;pwd=password;LINKs=tcpip(host=host_ip_address)"
and always the system gave me no error on connection in both cases
Ok guys that was kinda strange.
Let me explain the whole thing. I was doing that program for a customer that asked a software which could link my mysql db and a sybase db of another company.
The problem was that the DBMS of that company when is opened on the server block all kind of external editing to the db with which is connected.
So select query worked regularly but update and insert were blocked by that client...
I've passed 4 day with a perfect working program but that company didn't told me this "little" thing.
So be aware of DBMS they are cruel.

SQL Update statement doesn't update values when adding multiple columns otherwise it does

No exceptions, everything gets executed but the update doesn't happen!
Everything works ok when I have just #JIR parameter but now I added #Paragon and the update doesn't do it's job. No exception whatsoever data passed is OK...
I don't see anything wrong with this query does anyone know what could possibly be going wrong?
private static void InsertJIR(FisDnevni racun)
{
using (OleDbConnection con = new OleDbConnection(RegistarBlagajna.Modul.VezaNaBazu.ConnectionString))
{
try
{
con.Open();
OleDbCommand cmd = new OleDbCommand(#"
UPDATE FisDnevni
SET [JIR] = #JIR,
[Paragon] = #Paragon
WHERE BrojRacuna = #BrojRacuna"
, con);
cmd.Parameters.AddWithValue("#JIR", racun.JIR.Substring(0,37));
cmd.Parameters.AddWithValue("#BrojRacuna", racun.BrojRacuna);
cmd.Parameters.AddWithValue("#Paragon", racun.Paragon);
cmd.ExecuteNonQuery();
con.Close();
}
catch (Exception)
{
throw;
}
}
}
This is a good old problem - ensure the query parameters in OleDbParameter are declared in proper order like this:
using (OleDbConnection con = new OleDbConnection(RegistarBlagajna.Modul.VezaNaBazu.ConnectionString))
{
try
{
con.Open();
using (OleDbCommand cmd = new OleDbCommand(#"UPDATE FisDnevni SET [JIR] = #JIR, [Paragon] = #Paragon WHERE BrojRacuna = #BrojRacuna", con)
{
cmd.Parameters.AddWithValue("#JIR", racun.JIR.Substring(0,37));
// this must be the second parameter instead of third one
cmd.Parameters.AddWithValue("#Paragon", racun.Paragon);
cmd.Parameters.AddWithValue("#BrojRacuna", racun.BrojRacuna);
cmd.ExecuteNonQuery();
con.Close();
}
}
catch (Exception)
{
throw;
}
}
Note that OLE DB .NET Provider doesn't recognize named parameters for OleDbCommand when CommandType is set to Text, but it apparently does recognize the parameter order, hence as long as they're passed in proper order, it'll accepted as query parameter.
Related issue:
how to update a table using oledb parameters?
maybe i've just never used it, but why is there an # here?
OleDbCommand(#"
i also havent worked with C# in a while but is multi-line concatenation possible without a + or something?
thirdly why are you using [] on these column names? i don't see any special characters or spaces.
this post is sounding a lot more dikkish than i mean it to be, im not trying, just legit curious

what is wrong in my code to call a stored procedure

I Have created a Stored procedure dbo.test as follows
use sample
go
create procedure dbo.test as
DECLARE #command as varchar(1000), #i int
SET #i = 0
WHILE #i < 5
BEGIN
Print 'I VALUE ' +CONVERT(varchar(20),#i)
SET #i = #i + 1
END
Now i am created a c# console application to call the stored procedure as follows
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
namespace AutomationApp
{
class Program
{
public void RunStoredProc()
{
SqlConnection conn = null;
SqlDataReader rdr = null;
try
{
conn = new SqlConnection("Server=(TEST\\SQL2K5EXPRESS);DataBase=sample,IntegratedSecurity=SSPI");
conn.Open();
SqlCommand cmd = new SqlCommand("sample.dbo.test", conn);
cmd.CommandType = CommandType.StoredProcedure;
//cmd.ExecuteNonQuery();
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Console.WriteLine(String.Format("{0}, {1}",
rdr[0], rdr[1]));
}
}
catch(Exception ex)
{
Console.writeLine(ex.message);
}
finally
{
if (conn != null)
{
conn.Close();
}
if (rdr != null)
{
rdr.Close();
}
}
}
static void Main(string[] args)
{
Console.WriteLine("Hello World");
Program p= new Program();
p.RunStoredProc();
Console.Read();
}
}
}
O/P:
Hello World
//Could not find stored procedure 'test'.
A network-related or instance-specific error occurred while establishing a conne
ction to SQL Server. The server was not found or was not accessible. Verify that
the instance name is correct and that SQL Server is configured to allow remote
connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Serve
r/Instance Specified)
But when i try to run the program it was closing so i debugged the program then at exactly at executeReader() method it was showed that can not find the stored procedure "dbo.test"
and when i give the "EXEC dbo.test" at SSMS it display the result as i expected.
waht is wronng with this any Help greatly Appreciated.
Why are you looking in the master database?
Also, your code needed some cleanup:
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
namespace AutomationApp
{
class Program
{
public void RunStoredProc()
{
Console.WriteLine("\nTop 10 Most Expensive Products:\n");
using (SqlConnection conn =
new SqlConnection(
"Server=(local);DataBase=master;IntegratedSecurity=SSPI"))
{
conn.Open();
using (SqlCommand cmd =
new SqlCommand("dbo.test", conn) {
CommandType = CommandType.StoredProcedure})
{
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
Console.WriteLine(String.Format("{0}, {1}",
rdr[0], rdr[1]));
}
}
}
}
}
}
}
I would suggest it is related to teh permissions granted to the stored procedure.
Check out "GRANT EXECUTE <storedProc> TO <User>" you could also check the permissions in SSMS by right clicking on the stored proc.
I understand this is a test stored proc but it is not optimal to create stored procedures in the master database.
All the best :)
Just change your connection string:
conn = new SqlConnection("Server=(local);DataBase=master;IntegratedSecurity=SSPI");
You're hitting the master database. You want to hit whatever your database is called.
Alternatively, call the stored proc as dbname.dbo.test.
First of all - there's typo in your connection string - you need to use all semicolons - not semicolon once and commas the other time. Between DAtaBase= and IntegratedSEcurity, you have a comma - plus, it has to be "Integrated Security" (with a space!). Check out www.connectionstrings.com for the details on how to properly create a connection string.
Your original connection string in your post:
conn = new SqlConnection(
"Server=(TEST\\SQL2K5EXPRESS);DataBase=sample,IntegratedSecurity=SSPI");
should really be:
conn = new SqlConnection(
"Server=(TEST\\SQL2K5EXPRESS);DataBase=sample;Integrated Security=SSPI");
Once that would work, I think the main problem is that you're trying to pass in a SQL statement in the parameter #command to the stored procedure, which you execute inside the stored procedure (not in your current post, but in others you've posted), and you want to read out the rows returned by that statement.
But you have no way of being sure (short of parsing the SQL statement you're passing in) whether or not that SQL statement will actually indeed return values or whether it's a DDL statement like INSERT, CREATE TABLE or something.
So you have ADO.NET, calling a stored proc, which dynamically executes an arbitrary SQL statement, and you still want to be able to retrieve those results....
In my opinion, you need to rearchitect your approach - this will never work reliably - find another way to do what you're trying to do - there must be a way to do this with less dynamic execution of SQL inside a stored proc and stuff........ there's gotta be an easier way!
Marc
Have you tried just using "test" instead of "dbo.test"?
Your stored procedure doesn't return any results. Change your PRINT into SELECT.
You may be getting the error because ADO.NET doesn't know how to react to the status messages the print statement causes.
The SQL error you see is connecting to the server. It doesn't even get that far, so it isn't related to permissions at all. As far as your client goes, you'd get the same error if you connected to "Server=GroverCleveland\Instance1" (assuming it doesn't exist on your network).
I think that the problem is that you are wrapping the server name in parens, if you can connect to it fine using other SQL clients on the same client box. Try the following:
conn = new SqlConnection("Server=TEST\\SQL2K5EXPRESS;DataBase=sample;IntegratedSecurity=SSPI");
Marc is right about the semicolon, btw. Check out connectionstrings.com for details on that...

Categories

Resources