The application I am developing is meant to be a quick and easy tool to import data to our main app. So the user loads in a CSV, meddles with the data a little and pushes it up to the database.
Before the data is pushed to the database, I have a verification check going on which basically says, "Does a customer exist in the database with the same name, account and sort codes? If so, put their guid (which is known already) into a list."
The problem is, the result variable is always 0; this is despite the fact that there is duplicate test data already in my database which should show a result. Added to that, using SQL Profiler, I can't see a query actually being executed against the database.
I'm sure that the ExecuteScalar() is what I should be doing, so my attention comes to the Parameters I'm adding to the SqlCommand... but I'll be blowed if I can figure it... any thoughts?
string connectionString = Generic.GetConnectionString("myDatabase");
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand check = new SqlCommand("select COUNT(*) from Customers C1 INNER JOIN CustomerBank B1 ON C1.Id = B1.CustomerId WHERE C1.Name = #Name AND B1.SortCode = #SortCode AND B1.AccountNumber = #AccountNumber", conn);
foreach (DataRow row in importedData.Rows)
{
check.Parameters.Clear();
check.Parameters.Add("#Name", SqlDbType.NVarChar).Value = row["Name"].ToString();
check.Parameters.Add("#SortCode", SqlDbType.NVarChar).Value = row["SortCode"].ToString();
check.Parameters.Add("#AccountNumber", SqlDbType.NVarChar).Value = row["AccountNumber"].ToString();
Object result = check.ExecuteScalar();
int count = (Int32)result;
if (count > 0)
{
DuplicateData.Add((Guid)row["BureauCustomerId"]);
}
}
}
Clarification: importedData is a DataTable of the user's data held in this C# application. During the ForEach loop, each row has various columns, a few of those being Name, SortCode and AccountNumber. The values seem to get set in the parameters (but will verify now).
Related
I did not create and do not own this database. My job is usually just to put data in it, so I don't have to think too much about the DBA side. I am messing with a side project and can not figure out why I can't list all the table names. I have found several methods to gather this information, but none work for me in a c# context. I get 0 rows back every time. They do work when executed as queries in azure data studio. I get 99 rows back (the correct number of tables) no matter which method I use to enumerate the tables. My connection string specifies the database to use within the server.
The query named workingQuery returns the expected information (1 row with 15 fields). So I know my connection string is correct and my code is functional.
I have a test function that I am trying many queries on.
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
List<string> fields = new List<string>();
string workingQuery = "SELECT TOP (1) * FROM myRealTable";
string failingTablesQuery1 = "SELECT name FROM sysobjects WHERE xtype = 'U'";
string failingTablesQuery2 = "SELECT name AS table_name FROM sys.tables GO";
string failingTablesQuery3 = "SELECT TABLE_NAME FROM information_schema.tables WHERE TABLE_TYPE = 'BASE TABLE'";
using (var command = conn.CreateCommand())
{
command.CommandText = workingQuery;
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
for (int i = 0; i < reader.FieldCount; i++)
{
fields.Add(reader[i].ToString());
}
conn.Close();
return fields;
}
}
In addition to the raw sql queries I have also tried SqlConnection.GetSchema("Tables"). It also returns no rows.
I tried prepending USE myDatabaseName; to the front of the queries to no effect.
I can only assume this is an issue with the way the database is set up. Can anyone help me track down what is causing this issue?
SOLUTION:
My connection string had credentials that did not have the necessary permissions for this operation.
In SQL Server access to metadata is controlled by the VIEW DEFINITION permission. You might have permission to SELECT from a table, but not to view its definition or discover it in the catalog. By default any permission on an object implies VIEW DEFINITION, but it can be DENY'd to a user. See Metadata Visibility Configuration.
So check that you're using the same identity in both places and that that identity has VIEW DEFINITION permissions on the tables.
I am making something that requires MySQL. I have the saving done from in-game, which is simply done by INSERT.
I have a column that will have a password in and I need to check if the inputted password matched any of the rows and then if it is, get all of the contents of the row then save it to variables.
Does anyone have an idea how to do this in C#?
//////////////////////////
I have found how to save and get the string, however it will only get 1 string at a time :(
MySql.Data.MySqlClient.MySqlCommand command = conn.CreateCommand();
command.CommandText = "SELECT * FROM (player) WHERE (pass)";
command.ExecuteNonQuery();
command.CommandType = System.Data.CommandType.Text;
MySql.Data.MySqlClient.MySqlDataReader reader = command.ExecuteReader();
reader.Read();
ayy = reader.GetString(1);
print (ayy);
if(ayy == password){
//something
}
My best practice is to use MySQLDataAdapter to fill a DataTable. You can then iterate through the rows and try to match the password.
Something like this;
DataTable dt = new DataTable();
using(MySQLDataAdapter adapter = new MySQLDataAdaper(query, connection))
{
adapter.Fill(dt);
}
foreach(DataRow row in dt.Rows)
{
//Supposing you stored your password in a stringfield in your database
if((row.Field<String>("columnName").Equals("password"))
{
//Do something with it
}
}
I hope this compiles since I typed this from my phone. You can find a nice explanation and example here.
However, if you are needing data from a specific user, why not specificly ask it from the database? Your query would be like;
SELECT * FROM usercolumn WHERE user_id = input_id AND pass = input_pass
Since I suppose every user is unique, you will now get the data from the specific user, meaning you should not have to check for passwords anymore.
For the SQL statement, you should be able to search your database as follows and get only the entry you need back from it.
"SELECT * FROM table_name WHERE column_name LIKE input_string"
If input_string contains any of the special characters for SQL string comparison (% and _, I believe) you'll just have to escape them which can be done quite simply with regex. As I said in the comments, it's been a while since I've done SQL, but there's plenty of resources online for perfecting that query.
This should then return the entire row, and if I'm thinking correctly you should be able to then put the entire row into an array of objects all at once, or simply read them string by string and convert to values as needed using one of the Convert methods, as found here: http://msdn.microsoft.com/en-us/library/system.convert(v=vs.110).aspx
Edit as per Prix's comment: Data entered into the MySQL table should not need conversion.
Example to get an integer:
string x = [...];
[...]
var y = Convert.ToInt32(x);
If you're able to get them into object arrays, that works as well.
object[] obj = [...];
[...]
var x0 = Convert.To[...](obj[0]);
var x1 = Convert.To[...](obj[1]);
Etcetera.
I have a database with a large number of data (millions of rows), and also is updating during the day with large number of data, I have a back up of this database for reporting, so getting report of data does not affect on the performance of main database.
For syncing back up database with main database, I wrote a windows service which queries the main database and inserts new data into backup database... every time the query gets 5000 rows from the main database...
EDIT:
the query is like below:
const string cmdStr = "SELECT * FROM [RLCConvertor].[dbo].[RLCDiffHeader] WHERE ID >= #Start and ID <= #End";
Here is the code:
using (var conn = new SqlConnection(_connectionString))
{
conn.Open();
var cmd = new SqlCommand(cmdStr, conn);
cmd.Parameters.AddWithValue("#Start", start);
cmd.Parameters.AddWithValue("#End", end);
SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess);
while (reader.Read())
{
var rldDiffId = Convert.ToInt32(reader["ID"].ToString());
var rlcDifHeader = new RLCDiffHeader
{
Tech_head_Type = long.Parse(reader["Tech_head_Type"].ToString()),
ItemCode = long.Parse(reader["ItemCode"].ToString()),
SessionNumber = long.Parse(reader["SessionNumber"].ToString()),
MarketFeedCode = reader["MarketFeedCode"].ToString(),
MarketPlaceCode = reader["MarketPlaceCode"].ToString(),
FinancialMarketCode = reader["FinancialMarketCode"].ToString(),
CIDGrc = reader["CIDGrc"].ToString(),
InstrumentID = reader["InstrumentID"].ToString(),
CValMNE = reader["CValMNE"].ToString(),
DEven = reader["DEven"].ToString(),
HEven = reader["HEven"].ToString(),
MessageCodeType = reader["MessageCodeType"].ToString(),
SEQbyINSTandType = reader["SEQbyINSTandType"].ToString()
};
newRLCDiffHeaders.Add(rldDiffId, rlcDifHeader);
}
conn.Close();
}
but when I started the service... the performance of main database got worse... is the code not efficient? Is there any better way? Because I searched and found that dataReader is the best for this case... or should I use DataTable and SqlDataAdapter?
You cannot treat this an a correct answer or solution for your problem.
Since the comment goes big, I am providing a solution to you.
Can you try using the concept of Ad hoc queries
Using this you can query another database using the following way
SELECT a.*
FROM OPENROWSET('SQLNCLI', 'Server=Seattle1;Trusted_Connection=yes;',
'SELECT GroupName, Name, DepartmentID
FROM AdventureWorks2012.HumanResources.Department
ORDER BY GroupName, Name') AS a;
Read more
http://technet.microsoft.com/en-us/library/ms187569.aspx
http://technet.microsoft.com/en-us/library/ms190312.aspx
Since you are using a service, the service account surely have access to read the main db and insert to report db. I will suggest you to have a SP in your report DB , that can access the main DB using OpenRowSet and insert to it.
Query will be similar like this.
Insert into tbl
SELECT a.*
FROM OPENROWSET('SQLNCLI', 'Server=Seattle1;Trusted_Connection=yes;',
'SELECT GroupName, Name, DepartmentID
FROM AdventureWorks2012.HumanResources.Department
ORDER BY GroupName, Name') AS a;
Form the service, you need to invoke the SP.
We had a similar issue and this was done by openrowset and I don't know how much performance impact this can provide. But I suggest you to do a POC and just analyze it.
Once again please consider this as a suggestion.
I want to make an all in one query, or even a two step query that pulls from 3 tables.
Table #1: Games - this table holds a type of game and has a description of the game etc.
Table #2: GameProfiles - this holds an id from the table 'Games', so they both have a GamesId column. This table holds Games won, Games Lost, etc etc
Table #3: Games_WhateverGame - this is not a specific table, there are multiple tables, for instance if I have a game BasketBall, there is going to be a seperate table for it called Games_BasketBall and it has custom columns depending on the game. For example, Basketball would have a column for rebounds. This table would have its own primary key id.
I can easily pull the Games and GameProfiles together using an inner join on their common "GameId" column, but how do I make it so I can also pull 'Games_BasketBall' also in the same query, dynamically depending on the GamesId. I may be structuring this wrong, so I am open to suggestions. I just cant seem to think of a really fluid way of making this work correctly because each game will have different profile entities regardless so I want to make the relations to each table easy so I can pull everything in one query.
This code has the query WITHOUT the relation on to Games_Basketball, I want to be able to pull it all into one reader so it has the information correct.
using (SqlConnection myConnection = new SqlConnection(myConnectionString))
{
myConnection.Open();
String selectSql = "SELECT * FROM aspnet_GameProfiles INNER JOIN aspnet_Games ON aspnet_GameProfiles.GameId = aspnet_Games.GameId WHERE UserId = #UserId";
SqlCommand myCommand = new SqlCommand(selectSql, myConnection);
myCommand.Parameters.AddWithValue("#GameProfile", UserId);
reader = myCommand.ExecuteReader();
gameTable.DataSource = reader;
gameTable.DataBind();
myConnection.Close();
}
For yours current shema I would go for something like:
public enum GameType { Basketball, Snooker, ... }
void BindGameData(GameType gameType)
{
[ sql connection code ]
StringBuilder sb = new StringBuilder();
// those constant parts should be stored outside in config file
sb.append("SELECT * FROM aspnet_GameProfiles INNER JOIN aspnet_Games ON aspnet_GameProfiles.GameId = aspnet_Games.GameId ");
sb.append("INNER JOIN ");
sb.append("aspnet_" + gameType.toString()); // adopt to yours naming pattern
sb.append("ON aspnet_Games.GameId = ");
sb.append("aspnet_" + gameType.toString() + ".GameId");
sb.append("WHERE UserId = #UserId");
String selectSql = sb.toString();
[rest of yours sql connection code]
}
You could also use MARS (Mulitple Active Result Sets) to accomplish your goal. In MARS you use two sqldatareader at the same time.
Here is a small sample:
SqlDataReader rdrone = null;
SqlDataReader rdrtwo = null;
string connectionstring = "server=sugandha;initial catalog = Employeedetail;uid = sa;pwd= sa";MultipleActiveResultSets = true;
SqlConnection con = new SqlConnection(connectionstring);
SqlCommand cmdone = new SqlCommand("select * from Employee", con);
SqlCommand cmdtwo = new SqlCommand("select * from Employeedept", con);
con.Open();
rdrone = cmdone.ExecuteReader();
DataTable dtone = new DataTable();
dtone.Load(rdrone);
dataGridView1.DataSource = dtone;
rdrtwo = cmdtwo.ExecuteReader();
DataTable dttwo = new DataTable();
dttwo.Load(rdrtwo);
dataGridView2.DataSource = dttwo;
con.Close();
If you want to get all the information for all games at one time, it's not practical to do that in one query. And, you know, the user doesn't want to wait for you to do, say, 135 LEFT JOIN operations to get information from all the game "whatever" tables.
So, even though it's possible, it's not practical, and you really probably don't want to do that anyway. The user isn't likely to want to read through all that data, right?
Show just what the user needs, just when the user needs it. If the user clicks on "basketball", then you can query a view that has already joined the two or three tables you need to display information about the "basketball" game.
I have a simple problem with a not so simple solution... I am currently inserting some data into a database like this:
kompenzacijeDataSet.KompenzacijeRow kompenzacija = kompenzacijeDataSet.Kompenzacije.NewKompenzacijeRow();
kompenzacija.Datum = DateTime.Now;
kompenzacija.PodjetjeID = stranka.id;
kompenzacija.Znesek = Decimal.Parse(tbZnesek.Text);
kompenzacijeDataSet.Kompenzacije.Rows.Add(kompenzacija);
kompenzacijeDataSetTableAdapters.KompenzacijeTableAdapter kompTA = new kompenzacijeDataSetTableAdapters.KompenzacijeTableAdapter();
kompTA.Update(this.kompenzacijeDataSet.Kompenzacije);
this.currentKompenzacijaID = LastInsertID(kompTA.Connection);
The last line is important. Why do I supply a connection? Well there is a SQLite function called last_insert_rowid() that you can call and get the last insert ID. Problem is it is bound to a connection and .NET seems to be reopening and closing connections for every dataset operation. I thought getting the connection from a table adapter would change things. But it doesn't.
Would anyone know how to solve this? Maybe where to get a constant connection from? Or maybe something more elegant?
Thank you.
EDIT:
This is also a problem with transactions, I would need the same connection if I would want to use transactions, so that is also a problem...
Using C# (.net 4.0) with SQLite, the SQLiteConnection class has a property LastInsertRowId that equals the Primary Integer Key of the most recently inserted (or updated) element.
The rowID is returned if the table doesn't have a primary integer key (in this case the rowID is column is automatically created).
See https://www.sqlite.org/c3ref/last_insert_rowid.html for more.
As for wrapping multiple commands in a single transaction, any commands entered after the transaction begins and before it is committed are part of one transaction.
long rowID;
using (SQLiteConnection con = new SQLiteConnection([datasource])
{
SQLiteTransaction transaction = null;
transaction = con.BeginTransaction();
... [execute insert statement]
rowID = con.LastInsertRowId;
transaction.Commit()
}
select last_insert_rowid();
And you will need to execute it as a scalar query.
string sql = #"select last_insert_rowid()";
long lastId = (long)command.ExecuteScalar(sql); // Need to type-cast since `ExecuteScalar` returns an object.
last_insert_rowid() is part of the solution. It returns a row number, not the actual ID.
cmd = CNN.CreateCommand();
cmd.CommandText = "SELECT last_insert_rowid()";
object i = cmd.ExecuteScalar();
cmd.CommandText = "SELECT " + ID_Name + " FROM " + TableName + " WHERE rowid=" + i.ToString();
i = cmd.ExecuteScalar();
I'm using Microsoft.Data.Sqlite package and I do not see a LastInsertRowId property. But you don't have to create a second trip to database to get the last id. Instead, combine both sql statements into a single string.
string sql = #"
insert into MyTable values (null, #name);
select last_insert_rowid();";
using (var cmd = conn.CreateCommand()) {
cmd.CommandText = sql;
cmd.Parameters.Add("#name", SqliteType.Text).Value = "John";
int lastId = Convert.ToInt32(cmd.ExecuteScalar());
}
There seems to be answers to both Microsoft's reference and SQLite's reference and that is the reason some people are getting LastInsertRowId property to work and others aren't.
Personally I don't use an PK as it's just an alias for the rowid column. Using the rowid is around twice as fast as one that you create. If I have a TEXT column for a PK I still use rowid and just make the text column unique. (for SQLite 3 only. You need your own for v1 & v2 as vacuum will alter rowid numbers)
That said, the way to get the information from a record in the last insert is the code below. Since the function does a left join to itself I LIMIT it to 1 just for speed, even if you don't there will only be 1 record from the main SELECT statement.
SELECT my_primary_key_column FROM my_table
WHERE rowid in (SELECT last_insert_rowid() LIMIT 1);
The SQLiteConnection object has a property for that, so there is not need for additional query.
After INSERT you just my use LastInsertRowId property of your SQLiteConnection object that was used for INSERT command.
Type of LastInsertRowId property is Int64.
Off course, as you already now, for auto increment to work the primary key on table must be set to be AUTOINCREMENT field, which is another topic.
database = new SQLiteConnection(databasePath);
public int GetLastInsertId()
{
return (int)SQLite3.LastInsertRowid(database.Handle);
}
# How about just running 2x SQL statements together using Execute Scalar?
# Person is a object that has an Id and Name property
var connString = LoadConnectionString(); // get connection string
using (var conn = new SQLiteConnection(connString)) // connect to sqlite
{
// insert new record and get Id of inserted record
var sql = #"INSERT INTO People (Name) VALUES (#Name);
SELECT Id FROM People
ORDER BY Id DESC";
var lastId = conn.ExecuteScalar(sql, person);
}
In EF Core 5 you can get ID in the object itself without using any "last inserted".
For example:
var r = new SomeData() { Name = "New Row", ...};
dbContext.Add(r);
dbContext.SaveChanges();
Console.WriteLine(r.ID);
you would get new ID without thinking of using correct connection or thread-safety etc.
If you're using the Microsoft.Data.Sqlite package, it doesn't include a LastInsertRowId property in the SqliteConnection class, but you can still call the last_insert_rowid function by using the underlying SQLitePCL library. Here's an extension method:
using Microsoft.Data.Sqlite;
using SQLitePCL;
public static long GetLastInsertRowId(this SqliteConnection connection)
{
var handle = connection.Handle ?? throw new NullReferenceException("The connection is not open.");
return raw.sqlite3_last_insert_rowid(handle);
}