Microsoft.Data.SQLite parameters not working - c#

I'm building a database kiosk using Microsoft.Data.SQLite. I'm using parameterized queries when building commands. This WAS working until VS was having build problems, and after applying various updates (detailed below), my parameters are no longer being applied. Hardcoding the values into the commandText works.
I was previously using the basic
selectCommand.Parameters.Add("#Table", Table)
and I tried using a more explicit parameter. Here's the full command:
public static List<String> GetTables(string Table) // Get the Items in a Table
{
List<String> entries = new List<string>();
using (SqliteConnection db = new SqliteConnection(ConnectionString)) // the db
{
db.Open();
SqliteCommand selectCommand = new SqliteCommand("SELECT Item FROM #Table;", db);
selectCommand.Parameters.Add("#Table", SqliteType.Text).Value = Table;
SqliteDataReader query = selectCommand.ExecuteReader();
while (query.Read()) // while still reading data
{
entries.Add(query.GetString(0)); // add string to entries
}
db.Close();
}
return entries;
}
But the parameter still isn't being applied. Here's the full error:
SQLite Error 1: 'near "#Table": syntax error'.
at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
at Microsoft.Data.Sqlite.SqliteCommand.<PrepareAndEnumerateStatements>d__62.MoveNext()
at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior
at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader()
at DataAccessLibrary.DataAccess.GetTables(String Table)
at brogle.SelectionPage.<LoadItemGridContent>d__8.MoveNext()} Microsoft.Data.Sqlite.SqliteException
Clearly, #Table isn't being changed to the string Table, whose value is "Bulbs". (There is a table "Bulbs", and again, hardcoding that into the command works as expected.) Debugging shows that the command accepts the parameter #Table with value "Bulbs".
To solve my build issues (code analysis was throwing errors) I installed Microsoft.CodeAnalysis.FxCopAnalyzers, updated SQLitePCLRaw.bundle_winsqlite3 and Microsoft.NETCore.UniversalWindowsPlatform to latest stable, and updated VS to 15.9.7.
If you need more details about anything, I can provide. Thanks.

It's for parameters. You can not give table names that way, what you can do for workaround is this :
SqliteCommand selectCommand = new SqliteCommand("SELECT Item FROM "+Table, db);
For more detail please refer Retrieve data from the SQLite database official document.

Related

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.

Why is SQLite schema version in .NET always 1

I have a sqlite database. When I query the db directly via the command line, the schema_version result is 3078.
But when I do this in .NET, the result is always '1'.
Here's a snippet:
public static long GetInternalSchemaVersion(this SQLiteConnection con)
{
using (var cmd = con.CreateCommand())
{
cmd.CommandText = string.Format("PRAGMA schema_version;");
DataTable results;
using (results = new DataTable())
{
using (SQLiteDataAdapter da = new SQLiteDataAdapter(cmd))
{
da.Fill(results);
return results.ToEnumerable().First().GetInt32("schema_version");
}
}
}
}
Am I doing something wrong?
Ideally you would show the connection string you're using. The most likely case is that when you're connecting via .Net, you're not connecting to the same database. The schema version is auto-incremented by SQLite on schema change, so the fact that it's returning 1 suggests this is a new database. To verify, run another query to pull back some other data you expect to be there. You'll probably find that the db is empty.

MySQL and C# Getting data from DB and creating an associative array/object

I am new to C# and have been using PHP for Years.
The problem I am facing is that I want to create a method/function that will take an "sql query" as parameter and return whatever data is retrieved so that it can be used using the key/index/column_name.
What I have achieved
I have achieved is that I am able to access the data through index within the same function.
but I wont know the no. of columns that will return so I am unable to store it in an array.
Code
string ConnectionString = ConfigurationManager.ConnectionStrings["sqlcon"].ConnectionString;
MySqlConnection db;
db = new MySql.Data.MySqlClient.MySqlConnection(ConnectionString);
try
{
db.Open();
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = db;
cmd.CommandText = sql;
MySqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Console.WriteLine(rdr['areaId'].toString());
}
db.Close();
return true;
}
The problems
1. I do not know the number of Columns.
2. I cannot access the index or Column name.
I want to create an associative array of data with the column name as index and data as its data
EDIT
I am trying to build an application on C# using WPF with MySQL Database.
My first suggestion would be to use one of the micro ORMs like Dapper.net
This can be fetched via nuget. If you wish to retrieve an unknown array of data from a table, or number of tables, you could fetch it into an ExpandoObject and then enumerate over that. An example of looping over an ExpandoObject can be found here.
public Foo FetchSomeData(string query)
{
using (var cn = Connection)
{
var result = cn.Query(query);
//do something with result, and return it
return new Foo(result);
}
}
I'd have concerns about passing raw sql into the DB without at least checking it or using parameters as it could be a major security risk, especially if you allow users to generate the query and you don't vet it first.

Insert data from one SQL Database to a second one using C#

I dont know how to do this query in c#.
There are two databases and each one has a table required for this query. I need to take the data from one database table and update the other database table with the corresponding payrollID.
I have two tables in seperate databases, Employee which is in techData database and strStaff in QLS database. In the employee table I have StaffID but need to pull the PayrollID from strStaff.
Insert payrollID into Employee where staffID from strStaff = staffID from Employee
However I need to get the staffID and PayrollID from strStaff before I can do the insert query.
This is what I have got so far but it wont work.
cn.ConnectionString = ConfigurationManager.ConnectionStrings["PayrollPlusConnectionString"].ConnectionString;
cmd.Connection = cn;
cmd.CommandText = "Select StaffId, PayrollID From [strStaff] Where (StaffID = #StaffID)";
cmd.Parameters.AddWithValue("#StaffID", staffID);
//Open the connection to the database
cn.Open();
// Execute the sql.
dr = cmd.ExecuteReader();
// Read all of the rows generated by the command (in this case only one row).
For each (dr.Read()) {
cmd.CommandText = "Insert into Employee, where StaffID = #StaffID";
}
// Close your connection to the DB.
dr.Close();
cn.Close();
Assuminig, you want to add data to existing table, you have to use UPDATE + SELECT statement (as i mentioned in a comment to the question). It might look like:
UPDATE emp SET payrollID = sta.peyrollID
FROM Emplyoee AS emp INNER JOIN strStaff AS sta ON emp.staffID = sta.staffID
I have added some clarity to your question: the essential part is that you want to create a C# procedure to accomplish your task (not using SQL Server Management Studio, SSIS, bulk insert, etc). Pertinent to this, there will be 2 different connection objects, and 2 different SQL statements to execute on those connections.
The first task would be retrieving data from the first DB (for certainty let's call it source DB/Table) using SELECT SQL statement, and storing it in some temporary data structure, either per row (as in your code), or the entire table using .NET DataTable object, which will give substantial performance boost. For this purpose, you should use the first connection object to source DB/Table (btw, you can close that connection as soon as you get the data).
The second task would be inserting the data into second DB (target DB/Table), though from your business logic it's a bit unclear how to handle possible data conflicts if records with identical ID already exist in the target DB/Table (some clarity needed). To complete this operation you should use the second connection object and second SQL query.
The sample code snippet to perform the first task, which allows retrieving entire data into .NET/C# DataTable object in a single pass is shown below:
private static DataTable SqlReadDB(string ConnString, string SQL)
{
DataTable _dt;
try
{
using (SqlConnection _connSql = new SqlConnection(ConnString))
{
using (SqlCommand _commandl = new SqlCommand(SQL, _connSql))
{
_commandSql.CommandType = CommandType.Text;
_connSql.Open();
using (SqlCeDataReader _dataReaderSql = _commandSql.ExecuteReader(CommandBehavior.CloseConnection))
{
_dt = new DataTable();
_dt.Load(_dataReaderSqlCe);
_dataReaderSql.Close();
}
}
_connSqlCe.Close();
return _dt;
}
}
catch { return null; }
}
The second part (adding data to target DB/Table) you should code based on the clarified business logic (i.e. data conflicts resolution: do you want to update existing record or skip, etc). Just iterate through the data rows in DataTable object and perform either INSERT or UPDATE SQL operations.
Hope this may help. Kind regards,

Getting SqlBulkCopy to show up as sql in MiniProfiler

I'm using MiniProfiler to profile my sql commands.
One issue I'm dealing with now is repeated INSERT statements generated by linq.
I've converted them into a SqlBulkCopy command, however now it doesn't appear to record it in the sql view in MiniProfiler.
Would there even be an associated command string for a SqlBulkCopy?
Is it possible to get the bulk copy to appear in the list of sql commands?
Can I at least make it counted in the % sql bit?
I'm aware I could use MiniProfiler.Current.Step("Doing Bulk Copy") but that wouldn't count as SQL, and wouldn't show in the listing with any detail.
Current code below:
public static void BulkInsertAll<T>(this DataContext dc, IEnumerable<T> entities)
{
var conn = (dc.Connection as ProfiledDbConnection).InnerConnection as SqlConnection;
conn.Open();
Type t = typeof(T);
var tableAttribute = (TableAttribute)t.GetCustomAttributes(
typeof(TableAttribute), false).Single();
var bulkCopy = new SqlBulkCopy(conn)
{
DestinationTableName = tableAttribute.Name
};
//....
bulkCopy.WriteToServer(table);
}
You should be able to use CustomTimings to profile these. These are included in the new v3 version that is now available on nuget.
You can see some example usages of CustomTiming in the sample project where this is used to record http and redis events.
An example of how you could use it with SqlBulkCopy:
string sql = GetBulkCopySql(); // what should show up for the SqlBulkCopy event?
using (MiniProfiler.Current.CustomTiming("SqlBulkCopy", sql))
{
RunSqlBulkCopy(); // run the actual SqlBulkCopy operation
}

Categories

Resources