Create SQLite Database and table - c#

Within C# application code, I would like to create and then interact with one or more SQLite databases.
How do I initialize a new SQLite database file and open it for reading and writing?
Following the database's creation, how do I execute a DDL statement to create a table?

The next link will bring you to a great tutorial, that helped me a lot!
How to SQLITE in C#: I nearly used everything in that article to create the SQLite database for my own C# Application.
Preconditions
Download the SQLite.dll
either by addding the SQLite DLL's manually
or by using NuGet
Add it as a reference to your project
Refer to the dll from your code using the following line on top of your class: using System.Data.SQLite;
Code sample
The code below creates a database file and inserts a record into it:
// this creates a zero-byte file
SQLiteConnection.CreateFile("MyDatabase.sqlite");
string connectionString = "Data Source=MyDatabase.sqlite;Version=3;";
SQLiteConnection m_dbConnection = new SQLiteConnection(connectionString);
m_dbConnection.Open();
// varchar will likely be handled internally as TEXT
// the (20) will be ignored
// see https://www.sqlite.org/datatype3.html#affinity_name_examples
string sql = "Create Table highscores (name varchar(20), score int)";
// you could also write sql = "CREATE TABLE IF NOT EXISTS highscores ..."
SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection);
command.ExecuteNonQuery();
sql = "Insert into highscores (name, score) values ('Me', 9001)";
command = new SQLiteCommand(sql, m_dbConnection);
command.ExecuteNonQuery();
m_dbConnection.Close();
After you created a create script in C#, you might want to add rollback transactions. It will ensure that data will be committed at the end in one big piece as an atomic operation to the database and not in little pieces, where it could fail at 5th of 10th query for example.
Example on how to use transactions:
using (TransactionScope transaction = new TransactionScope())
{
//Insert create script here.
// Indicates that creating the SQLiteDatabase went succesfully,
// so the database can be committed.
transaction.Complete();
}
3rd party edit
To read records you can use ExecuteReader()
sql = "SELECT score, name, Length(name) as Name_Length
FROM highscores WHERE score > 799";
command = new SQLiteCommand(sql, m_dbConnection);
SQLiteDataReader reader = command.ExecuteReader();
while(reader.Read())
{
Console.WriteLine(reader[0].ToString() + " "
+ reader[1].ToString() + " "
+ reader[2].ToString());
}
dbConnection.Close();
See also this transactionscope example

Related

How to fix SQL Injection Issue of truncation of table

Below is the line of code where I truncate table records. The table value is coming from the front end. In my Veracode scan, it is showing SQL injection. How can I avoid this? I cannot create a stored procedure as the connection string is dynamic where I need to truncate this table. Is there another approach?
SqlCommand cmd = connection.CreateCommand();
cmd.Transaction = transaction;
cmd.CommandText = "TRUNCATE TABLE " + tablename;
cmd.ExecuteNonQuery();
You need dynamic sql:
string sql = #"
DECLARE #SQL nvarchar(150);
SELECT #SQL = 'truncate table ' + quotename(table_name) + ';'
FROM information_schema.tables
WHERE table_name = #table;
EXEC(#SQL);";
using (var connection = new SqlConnection("connection string here"))
using (var cmd = new SqlCommand(sql, connection))
{
cmd.Transaction = transaction;
cmd.Parameters.Add("#table", SqlDbType.NVarChar, 128).Value = tablename;
connection.Open();
cmd.ExecuteNonQuery();
}
This is one of very few times dynamic SQL makes things more secure, rather than less. Even better, if you also maintain a special table in this database listing other tables users are allowed to truncate, and use that rather than information_schema to validate the name. The idea of letting users just truncate anything is kind of scary.
Parametrized or not, you can make it only a little more secured in this case. Never totally secured. For this you need
create table TruncMapping in DB where you store
id guid
statement varchar(300)
your data will look like
SOME-GUID-XXX-YYY, 'TRUNCATE TABLE TBL1'
In your front end use a listbox or combobox with text/value like "Customer Data"/"SOME-GUID-XXX-YYY"
In your code use ExecuteScalar to execute Select statement from TruncMapping where id = #1 , where id will be parameterized GUID from combo value
Execute your truncate command using ExecuteNonQuery as you do now but with a retrieved string from previous call.
Your scan tool will most likely choke. If it is still thinking code is unsafe, you can safely point this as false positive because what you execute is coming from your secured DB. Potential attacker has no way to sabotage your "non-tuncatable tables" because they are not listed in TruncMapping tables.
You've just created multi-layered defense against sql injection.
here is one way to hide it from scanning tools
private const string _sql = "VFJVTkNBVEUgVEFCTEU=";
. . . .
var temp = new { t = tablename };
cmd.CommandText =
Encoding.ASCII.GetString(Convert.FromBase64String(_sql)) + temp.t.PadLeft(temp.t.Length + 1);
security by obscurity

System.Data.SqlClient.SqlException: 'Invalid object name when trying to insert data in database (C#, Visual Studio)

First I would like to say that I thought that my problem was easily solved but after a lot of trying and searching I am not making any progress (I am also a complete beginner when it comes to databases).
I made a database with Microsoft SQL Server and called it UltimatePokerDB.
I added a table MyTable
I added two columns sevenKeys and sevenValues
this is visible in Visual Studio
Image of my Server Explorer in visual studio
and makes this SQL code
CREATE TABLE MyTable
(
[sevenKeys] BINARY(56) NOT NULL PRIMARY KEY,
[SevenValues] BINARY(48) NOT NULL
)
I have the following code written in my Main method
string provider = "System.Data.SqlClient";
string connectionstring = "Server=localhost;Database=master;Trusted_Connection=True;";
byte[] one = new byte[7];
byte[] two = new byte[6];
DbProviderFactory factory = DbProviderFactories.GetFactory(provider);
using (SqlConnection cnn = new SqlConnection(connectionstring))
{
string sql = "insert into MyTable (sevenKeys, sevenValues) values(#first,#last)";
cnn.Open();
using (SqlCommand cmd = new SqlCommand(sql, cnn))
{
cmd.Parameters.AddWithValue("#first", one);
cmd.Parameters.AddWithValue("#last", two);
cmd.ExecuteNonQuery();
Console.WriteLine("row inserted");
}
}
I get an error at cmd.ExecuteNonQuery() and it says: System.Data.SqlClient.SqlException: 'Invalid object name 'MyTable'.'
Basically Im giving it the wrong name but I have no clue what it wants me to do...
You've specified in your connection string to use the Database master. You should probably be using the database your table is in, which is probably not master. In fact it looks like it should be UltimatePokerDB from your screenshot.

Prepared MySQL Statement fails insert with no error

I'm using MySQL to try and add a new user to my database. User got an Id, a First Name, a Last Name and a Date of Birth. But when I run the code below (And run conn.close() after I'm done) the database tells me (using HeidiSQL) that in the Table Overview there is now a new row in the table but when I open the Data Tab to look at the rows, there is nothing. It's empty. Running a COUNT(*) also returns 0.
using (MySqlTransaction transaction = conn.BeginTransaction())
{
using (MySqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "INSERT INTO USERS(NAME_FIRST,NAME_LAST,DATE_OF_BIRTH) VALUES(#nameFirst,#nameLast,#dateOfBirth)";
cmd.Transaction = transaction;
cmd.Parameters.AddWithValue("#nameFirst", user.NameFirst);
cmd.Parameters.AddWithValue("#nameLast", user.NameLast);
cmd.Parameters.AddWithValue("#dateOfBirth", user.DateOfBirth);
cmd.Prepare();
cmd.ExecuteNonQuery();
lastInsertId = (uint)cmd.LastInsertedId;
}
}
I get no errors. Nothing shows up in any log and everyone sees the same as me.
What am I doing wrong?
It feels like it's the use of begintransaction which starts a transaction. This means autocommit=false for the entirety of the transaction.
After ExecuteNonQuery Do a transaction.Commit(); and see if they show up.
More Info Here

How To avoid Generate Sqlite DB Every time i start the program instead of one time

i'v used this code to generate sqlite Database ..
private static SQLiteConnection GenData()
{
SQLiteConnection.CreateFile("MyDatabase.sqlite");
SQLiteConnection m_dbConnection;
m_dbConnection new SQLiteConnection("Data Source=MyDatabase.sqlite;Version=3;");
m_dbConnection.Open();
string createTableQuery = #"CREATE TABLE IF NOT EXISTS [MyTable] (
[ID] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
[Value] VARCHAR(2048) NULL
)";
SQLiteCommand command = new SQLiteCommand(createTableQuery, m_dbConnection);
command.ExecuteNonQuery();
return m_dbConnection;
}
and i use it in button click to insert Data and Create DB
private void insertintoDB(string Textbox)
{
SQLiteConnection m_dbConnection = GenData();
string sql = "insert into MyTable (Value) values ('" + Textbox + "')";
SQLiteCommand commmand = new SQLiteCommand(sql, m_dbConnection);
commmand.ExecuteNonQuery();
}
insertintoDB(textbox1.text)
and i put GenData() in load event but every time i use the application .. it auto Generate the database and i need it to be only one time
Do a simple file check at the location your database is getting created at (typically this is App_Data, though you may want to specify a different location using the appropriate environment variables).
Then create a conditional statement to execute you "CreateFile" command only if the file doesn't exist.
Just add an if statement before your Create File
private static SQLiteConnection GenData()
{
if (!System.IO.File.Exists("MyDatabase.sqlite"))
SQLiteConnection.CreateFile("MyDatabase.sqlite");
.....
This will check whether a file exists before creating it.

SqlBulkInsert with a DataTable to a Linked Server

I'm working with 2 SQL 2008 Servers on different machines. The server names are source.ex.com, and destination.ex.com.
destination.ex.com is linked to source.ex.com and the appropriate permissions are in place for source.ex.com to write to a database called bacon-wrench on destination.ex.com
I've logged into source.ex.com via SMS and tested this query (successfully):
INSERT INTO [destination.ex.com].[bacon-wrench].[dbo].[tblFruitPunch]
(PunchID, BaconID) VALUES (4,6);
In a C# .NET 4.0 WebPage I connect to source.ex.com and perform a similar query (successfully):
using(SqlConnection c = new SqlConnection(ConfigurationManager.ConnectionStrings["SOURCE"].ConnectionString))
{
c.Open();
String sql = #"
INSERT INTO [destination.ex.com].[bacon-wrench].[dbo].[tblFruitPunch]
(PunchID, BaconID) VALUES (34,56);";
using(SqlCommand cmd = new SqlCommand(sql, c))
{
cmd.ExecuteNonQuery();
}
}
For small sets of insert statements (say 20 or less) doing something like this performs fine:
using(SqlConnection c = new SqlConnection(ConfigurationManager.ConnectionStrings["SOURCE"].ConnectionString))
{
c.Open();
String sql = #"
INSERT INTO [destination.ex.com].[bacon-wrench].[dbo].[tblFruitPunch]
(PunchID, BaconID) VALUES (34,56);
INSERT INTO [destination.ex.com].[bacon-wrench].[dbo].[tblFruitPunch]
(PunchID, BaconID) VALUES (22,11);
INSERT INTO [destination.ex.com].[bacon-wrench].[dbo].[tblFruitPunch]
(PunchID, BaconID) VALUES (33,55);
INSERT INTO [destination.ex.com].[bacon-wrench].[dbo].[tblFruitPunch]
(PunchID, BaconID) VALUES (1,2);";
using(SqlCommand cmd = new SqlCommand(sql, c))
{
cmd.ExecuteNonQuery();
}
}
I'm trying to do something like this with around 20000 records. The above method takes 11 minutes to complete -- which I assume is the server sreaming at me to make it some kind of bulk operation. From other StackOverflow threads the SqlBulkCopy class was recommended and it takes as a parameter DataTable, perfect!
So I build a DataTable and attempt to write it to the server (fail):
DataTable dt = new DataTable();
dt.Columns.Add("PunchID", typeof(int));
dt.Columns.Add("BaconID", typeof(int));
for(int i = 0; i < 20000; i++)
{
//I realize this would make 20000 duplicate
//rows but its not important
dt.Rows.Add(new object[] {
11, 33
});
}
using(SqlConnection c = new SqlConnection(ConfigurationManager.ConnectionStrings["SOURCE"].ConnectionString))
{
c.Open();
using(SqlBulkCopy bulk = new SqlBulkCopy(c))
{
bulk.DestinationTableName = "[destination.ex.com].[bacon-wrench].[dbo].[tblFruitPunch]";
bulk.ColumnMappings.Add("PunchID", "PunchID");
bulk.ColumnMappings.Add("BaconID", "BaconID");
bulk.WriteToServer(dt);
}
}
EDIT2: The below message is what I'm attempting to fix:
The web page crashes at bulk.WriteToServer(dt); with an error message Database bacon-wrench does not exist please ensure it is typed correctly. What am I doing wrong? How do I change this to get it to work?
EDIT1:
I was able to speed up the query significantly using the below syntax. But it is still very slow for such a small record set.
using(SqlConnection c = new SqlConnection(ConfigurationManager.ConnectionStrings["SOURCE"].ConnectionString))
{
c.Open();
String sql = #"
INSERT INTO [destination.ex.com].[bacon-wrench].[dbo].[tblFruitPunch]
(PunchID, BaconID) VALUES
(34,56),
(22,11),
(33,55),
(1,2);";
using(SqlCommand cmd = new SqlCommand(sql, c))
{
cmd.ExecuteNonQuery();
}
}
If you are using SQL Server 2008+, you can introduce a Table user datatype. Prepare the type, receiving table and stored procedure something like below. Data type and stored procedure is on the local system. I generally have an if statement in the code detecting whether the table is remote or local, remote I do this, local I use SqlBulkCopy.
if(TYPE_ID(N'[Owner].[TempTableType]') is null)
begin
CREATE TYPE [Owner].[TempTableType] AS TABLE ( [PendingID] uniqueidentifier, [Reject] bit)
end
IF NOT EXISTS (SELECT * FROM [LinkedServer].[DatabaseOnLS].sys.tables where name = 'TableToReceive')
EXEC('
CREATE TABLE [DatabaseOnLS].[Owner].[TableToReceive] ( [PendingID] uniqueidentifier, [Reject] bit)
') AT [LinkedServer]
else
EXEC('
TRUNCATE TABLE [DatabaseOnLS].[Owner].[TableToReceive]
') AT [LinkedServer]
CREATE PROCEDURE [Owner].[TempInsertTable]
#newTableType TempTableType readonly
AS
BEGIN
insert into [LinkedServer].[DatabaseOnLS].[Owner].[TableToReceive] select * from #newTableType
END
In the C# code you can then do something like this to insert the DataTable into the table on the linked server (I'm using an existing UnitOfWork, which already have a connection and transaction):
using (var command = new SqlCommand("TempInsertTable",
oUoW.Database.Connection as SqlConnection) { CommandType = CommandType.StoredProcedure }
)
{
command.Transaction = oUoW.Database.CurrentTransaction as SqlTransaction;
command.Parameters.Add(new SqlParameter("#newTableType", oTempTable));
drResults = command.ExecuteReader();
drResults.Close();
}
After trying a number of things including linked server settings, collations, synonyms, etc., I eventually got to this error message:
Inserting into remote tables or views is not allowed by using the BCP utility or by using BULK INSERT.
Perhaps you can bulk insert to a staging table on your local server (your code works fine for this) and then insert from that staging table to your linked server from there, followed by a local delete of the staging table. You'll have to test for performance.

Categories

Resources