Can I get the result directly when SqlDependency fires? - c#

I have set up a dependency as follows. I get a call back whenever a new row is added.
But when I get call back, I then need to run a similar query to get the appropriate rows.
Is it possible to get the result of this dependency query sent with the callback?
public void InitialiseDependencyForFills()
{
string cmdText = "SELECT [Symbol] FROM [Jug].[Orders] WHERE [AccountIdent] = 'Jack' and [Status] = 'NEW'";
using (SqlCommand command = new SqlCommand(cmdText, conn))
{
SqlDependency FilledDependency = new SqlDependency(command);
FilledDependency.OnChange += new OnChangeEventHandler(OnDependencyForFillsChange);
using (SqlDataReader reader = command.ExecuteReader())
{
// Process the DataReader.
}
}
}

Related

How to return specific row from database that include image path

I write below code that correctly returns an image that its path stored in the database.
[HttpGet("{id}")]
public IActionResult RetrieveFile(int id)
{
string pathImage = "";
DataTable table = new DataTable();
string query = #"select image from mydb.courses where id=#id";
string sqlDataSource = _configuration.GetConnectionString("UsersAppCon");
MySqlDataReader myReader;
using (MySqlConnection mycon = new MySqlConnection(sqlDataSource))
{
mycon.Open();
using (MySqlCommand myCommand = new MySqlCommand(query, mycon))
{
myCommand.Parameters.AddWithValue("#id", id);
pathImage = (string)myCommand.ExecuteScalar();
mycon.Close();
}
}
var path = #$"{pathImage}";
var fs = new FileStream(path, FileMode.Open);
return File(fs, "image/jpeg");
}
Furthermore, I want to return the id, price, and name with the image from the database and send it to the client.
What changes should I make to the above code to send me What I want?
You cannot use ExecuteScalar, but you need to call ExecuteReader to get back an MySqlDataReader and then get the single inputs from the reader fields. and of course, you should change the query to get the required fields
string query = #"select id,price,name,image from mydb.courses where id=#id";
string sqlDataSource = _configuration.GetConnectionString("UsersAppCon");
using (MySqlConnection mycon = new MySqlConnection(sqlDataSource))
{
mycon.Open();
using (MySqlCommand myCommand = new MySqlCommand(query, mycon))
{
myCommand.Parameters.AddWithValue("#id", id);
// Then you use the reader to get the single field values
using(MySqlDataReader myReader = myCommand.ExecuteReader())
{
// Always check if the where clause produces records to read
if(myReader.Read())
{
// I have assumed the datatype for the fields. Change GetXXXX if different
pathImage = myReader.GetString("image");
id = myReader.GetInt32("id");
price = myReader.GetDecimal("price");
name = myReader.GetString("name");
}
}
}
}
Notice that you don't need to close the connection when it is declared inside a using statement. Also it is better to not use AddWithValue albeit in case of integers its problems are not relevant and MySql seems to be a bit more resilient than other db

How to execute another MySqlDataReader for each read ID?

I'm trying to get from my database some data, each of that data may have some attributes, so my logic was while i'm getting all data so while the MySqlDataReader is executed i was going to execute the query for each id of data i got to get it's attributes.
But i run in to error: 'There is already an open DataReader associated with this Connection' so my guess is that i can't run at the same time the MySqlDataReader so at this point, which would be the best approach to get attributes for each data?
Should i just cycle on each Plu element after i've added them to the list or is there a better solution?
Here is the function where i get the data (Plu object)
public IEnumerable<Plu> GetPlu(string piva, int menu)
{
string connectionString = $"CONSTR";
using var connection = new MySqlConnection(connectionString);
connection.Open();
var sql = #"QUERY";
using var cmd = new MySqlCommand(sql, connection);
cmd.Parameters.AddWithValue("#menu", menu);
cmd.Prepare();
using MySqlDataReader reader = cmd.ExecuteReader();
List<Plu> plu = new List<Plu>();
while (reader.Read())
{
plu.Add(new Plu(
(int)reader["ID_PLUREP"],
(string)reader["CODICE_PRP"],
(string)reader["ESTESA_DES"],
(string)reader["DESCR_DES"], (float)reader["PRE_PRP"],
reader.IsDBNull(reader.GetOrdinal("IMG_IMG")) ? null : (string)reader["IMG_IMG"],
Attributi(connection, (int)reader["ID_PLUREP"])
));
}
return plu;
}
And here is function Attributi which return the IEnumerable of attributes for each Plu
public IEnumerable<Plu.Attributi> Attributi(MySqlConnection connection, int idplu)
{
var sql = #"QUERY";
using var cmd = new MySqlCommand(sql, connection);
cmd.Parameters.AddWithValue("#idplu", idplu);
cmd.Prepare();
List<Plu.Attributi> attributi = new List<Plu.Attributi>();
using MySqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
attributi.Add(new Plu.Attributi(
reader.IsDBNull(reader.GetOrdinal("BCKCOL_ATT")) ? null : (string)reader["BCKCOL_ATT"],
reader.IsDBNull(reader.GetOrdinal("FORCOL_ATT")) ? null : (string)reader["FORCOL_ATT"],
reader.IsDBNull(reader.GetOrdinal("DESCR_ATT")) ? null : (string)reader["DESCR_ATT"]
));
}
return null;
}
You can't use an open connection with a reader already executing. Open a new connection in Attributi.
public IEnumerable<Plu.Attributi> Attributi(int idplu)
{
var sql = #"QUERY";
using var connection = new MySqlConnection(connectionString)
{
connection.Open();
using var cmd = new MySqlCommand(sql, connection)
{
cmd.Parameters.AddWithValue("#idplu", idplu);
cmd.Prepare();
List<Plu.Attributi> attributi = new List<Plu.Attributi>();
using MySqlDataReader reader = cmd.ExecuteReader()
{
while (reader.Read())
{
attributi.Add(new Plu.Attributi(
reader.IsDBNull(reader.GetOrdinal("BCKCOL_ATT")) ? null : (string)reader["BCKCOL_ATT"],
reader.IsDBNull(reader.GetOrdinal("FORCOL_ATT")) ? null : (string)reader["FORCOL_ATT"],
reader.IsDBNull(reader.GetOrdinal("DESCR_ATT")) ? null : (string)reader["DESCR_ATT"]
));
}
return null;
}
}
}
BTW, your usage of using is totally off. You need a block after the using statement where you deal with everything regarding the IDisposable object.
EDIT: Apparently that's a new .NET Core 3.1 feature.
For the more general case, my experience with MySQL has lead me to always "free" my reader with:
MySqlDataReader reader = cmd.ExecuteReader();
DataTable dataTable = new DataTable();
dataTable.Load(reader);
Then working from the DataTable rather than the MySqlDataReader, you can then reuse the connection as you prefer.

C# Populate Object

I know people are going to scream that this topic is all over the internet. I know, I've read them. And I still don't understand it. I simply want to populate my object from the results of a stored procedure. Now this stored procedure takes at least 2 parameters - an action and what to find.
#Action
#customername
The #Action simply determine what the stored procedure needs to do and returns the results. So for example if I want to update a customer, I'd call the sp through my object:
public class Customer()
{
//properties
public int UpdateCustomer()
{
using (SQLConnection connection = new SqlConnection(Helper.CnnVal("DataConnection")))
{
SQLCommand = new SqlCommand(Helper.Procedure("Customer"), connection);
command.CommandType = CommandType.StoredProcedure;
SqlParameterCollection parameterCollection = command.Parameters;
parameterCollection.Add("#Action", SqlDbType.NVarChar, -1).Value = "Update"
//complete the rest of it....
}
}
}
This works well. So the problem arises when I simply want to populate the object with the results of the sp. In this case I would pass "Retrieve" as the #Action parameter and this.customer_name as the #customername parameter to the sp.
But how do I put the results from the stored procedure into the object?
I have this...
public void GetCustomer()
{
using (SQLConnection connection = new SqlConnection(Helper.CnnVal("DataConnection")))
{
var retrieval = new DynamicParameters();
retrieval.Add("#Action", "Retrieve");
retrieval.Add("#name", this.customer_Name);
connection.Open():
connection.Execute(Helper.Procedure("Customer"), retrieval, commandType: CommandType.StoredProcedure);
}
}
But I don't think it's working.
Back a long time ago I used to run a "fetch" for PHP when I needed to populate an object. Should I go back to this?
You need to execute a SqlReader on the command, Something like this:
using (var connection = new SqlConnection("Connection"))
using (var command = new SqlCommand("Retrieve", connection))
{
command.CommandType = System.Data.CommandType.StoredProcedure;
command.Parameters.AddWithValue("#Action", "Retrieve");
command.Parameters.AddWithValue("#name", this.customer_Name);
connection.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
var item = new YourClass();
// You can use GetX() methods to get the value of the fields
item.Name = reader.GetString("name");
// You can also access the fields by using bracket notation
item.Age = (int)reader["age"];
// Be careful of nullable fields though!
}
}
}
Using #Encrypt0r advice and guidance I got it working:
public void GetCustomer() {
using (SqlConnection connection = new SqlConnection(Helper.CnnVal("DataConnection"))) {
SqlCommand command = new SqlCommand(Helper.Procedure("Customer"), connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#Action", "Retrieve");
command.Parameters.AddWithValue("#name", this.customer_name);
connection.Open();
using (var reader = command.ExecuteReader()) {
while (reader.Read()) {
this.tbl_id = (int)reader["tbl_id"];
this.customer_name = (string)reader["customer_name"];
this.customer_id = reader.GetInt32(customer_id);
this.customer_address = (string)reader["customer_address"];
this.customer_city = (string)reader["customer_city"];
this.customer_state = (string)reader["customer_state"];
this.customer_zip = reader.GetInt32(customer_zip);
}
}

SignalR SqlDependency breaks when I make SqlCommand generic

I am using SignalR to receive updates made to the database. I tried to make my method for doing this generic as shown below, however, this breaks the SQL dependency as it does not fire when there is a change in the DB. I have narrowed down the source of the problem to the SQL command which seems to stop it from working.
public IEnumerable<T> GetAllMessages<T>() where T : new()
{
var messages = new List<T>();
using (var connection = new SqlConnection(_connString))
{
connection.Open();
using (var command = new SqlCommand(#"SELECT * FROM [dbo]." + typeof(T).Name, connection))
{
command.Notification = null;
var dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
var reader = command.ExecuteReader();
while (reader.Read())
{
var row = new T();
ConvertReaderToRelevantModel(reader, row);
messages.Add(row);
}
}
}
return messages;
}
If I change the SQL command to the snippet below it works as expected:
using (var command = new SqlCommand(#"SELECT [ID],
[Name], [Number], [DateLastUpdated] FROM [dbo].[HeartBeats]", connection))
What is stopping this from working and how can I resolve this issue?
typef(T).Name is not what you expect. put a breakpoint and take a look.

How to use C# connect to mysql and get json data?

As mentioned above:
I'm using C# to connect to a MySQL database and I want to read JSON data type.
I use the method MySqlCommand.ExecuteReader:
using (MySqlConnection sconn = new MySqlConnection(sqlConnectString))
{
sconn.Open();
String sql_Command = #"SELECT `id` FROM orders.jsontest;";
using (MySqlCommand scmd = new MySqlCommand(sql_Command, sconn))
{
**MySqlDataReader sdr = scmd.ExecuteReader();** // fatal error
DataTable datatable = new DataTable();
// ...
}
}
Can it be that I cannot use ExecuteReader here?
I know this question is old, but just in case you do not yet have a solution to your problem or anyone else encounters a similar problem, the following code should work for you:
private IEnumerable<int> GetIds()
{
using (MySqlConnection connection = new MySqlConnection(connectionString))
{
connection.Open();
string commandText = #"SELECT id FROM jsontest"; // Assuming that `orders` is your database, then you do not need to specify it here.
using (MySqlCommand command = new MySqlCommand(commandText, connection))
{
MySqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
yield return reader.GetInt32(0);
}
}
}
}
Now what you should pay attention to is this line
while (reader.Read())
which fetches results from the jsontest table as long as the MySqlDataReader can still read valid results and this line
yield return reader.GetInt32(0);
which instructs the reader to get and return each record of the fetched table one at a time as an Int32 (int). You need to change this if your tables column type is not INT.
Since you selected just one column (i.e. "SELECT id"), the parameter is 0, because your fetched resul table consists of one column only.
Additionally, in your code you seem to want to get the results as a DataTable; if so, you should use MySqlDataAdapter instead of the MySqlDataReader as follows:
DataTable resultTable = new DataTable("ResultTable");
MySqlDataAdapter adapter = new MySqlDataAdapter(command);
adapter.Fill(table);
Correct your sql command
String sql_Command = #"SELECT id FROM orders.jsontest";

Categories