How to get UUID generated by MySQL into a C# varia

2019-07-30 16:35发布

问题:

Here is the query:

string query = @"INSERT INTO session (PK_Id, user_id, login_time, machine_ip, machine_fingerprint) 
                             VALUES (UUID(), @UId, @LogInTime, @MIp, @MFingerPrint);
                ";

Now I need this last inserted id back, which is a UUID generated by MySQL. As far as I read there is no select_last_insert_id() function for UUIDs!! And I read for php you could assign UUID() function first to a variable and then return that value. But how to go about that in C#?

Something like this, but not exactly:

string query = @"INSERT INTO session (PK_Id, user_id, login_time, machine_ip, machine_fingerprint) 
                             VALUES (@UUID = SELECT UUID(), @UId, @LogInTime, @MIp, @MFingerPrint);
                ";                  //how to do this here?

Here is more of my code:

string query = @"INSERT INTO session (PK_Id, user_id, login_time, machine_ip, machine_fingerprint) 
                 VALUES (@UUID = SELECT UUID(), @UId, @LogInTime, @MIp, @MFingerPrint);
                ";

try
{
    if (_conn.State != ConnectionState.Open)
        _conn.Open();
    MySqlCommand cmd = new MySqlCommand(query, _conn);
    cmd.Parameters.AddWithValue("@UId", Utility.usr.Id);
    cmd.Parameters.AddWithValue("@LogInTime", DateTime.Now);
    cmd.Parameters.AddWithValue("@MIp", GetMachineIP());
    cmd.Parameters.AddWithValue("@MFingerPrint", GetHardwareFingerPrint());

    var s= Convert.ToString(cmd.ExecuteScalar()); //this returns an empty string :(
    //I need to get it to any .NET data type, string, or Guid or byte[] or anything. 

But I need this datatype of s to be used in another WHERE clause in a query like this:

string query = @"UPDATE session SET logout_time = @LogOutTime 
                 WHERE user_id = @UId AND PK_Id = @SessionId";

try
{
    if (_conn.State != ConnectionState.Open)
        _conn.Open();
    MySqlCommand cmd = new MySqlCommand(query, _conn);
    cmd.Parameters.AddWithValue("@UId", Utility.usr.Id);
    cmd.Parameters.AddWithValue("@SessionId", s);
    cmd.Parameters.AddWithValue("@LogOutTime", DateTime.Now);
    cmd.ExecuteScalar();

Here @"SessionId" is the UUID field in the same table. So basically, how can I get the MySQL varbinary field in C# so that I could use that type to update by specifying WHERE in another query?

In MySQL table the UUID field is varbinary (I hope to see some solution that is not another php link or that is not asking me to switch to char datatype in the database :) ).

Edit: The problem here is we have already added plenty of UUIDs generated by MySQL into the table, so I'm a bit apprehensive about changing MySQL UUID to .NET Guid. If that's the only workaround, I'll consider that. Just that this is the first time we needed the inserted UUID value back so that I can update in another query another point of time.

A sub question: Is .NET Guid exactly the same thing as MySQL UUID?

回答1:

I think you can go ahead with your earlier implementation without having to rely on MS Guid, but I fear I am too late :)

string query = @"INSERT INTO session (PK_Id, user_id, login_time, machine_ip, machine_fingerprint) 
                             VALUES (UUID(), @UId, @LogInTime, @MIp, @MFingerPrint); 
                 SELECT PK_Id FROM session WHERE login_time=@LogInTime AND machine_fingerprint=@MFingerPrint; //or something similar which gives you the exact same id - UUID
                ";

try
{
    if (_conn.State != ConnectionState.Open)
        _conn.Open();
    MySqlCommand cmd = new MySqlCommand(query, _conn);
    cmd.Parameters.AddWithValue("@UId", Utility.usr.Id);
    cmd.Parameters.AddWithValue("@LogInTime", DateTime.Now);
    cmd.Parameters.AddWithValue("@MIp", GetMachineIP());
    cmd.Parameters.AddWithValue("@MFingerPrint", GetHardwareFingerPrint());

    MySqlDataReader r = cmd.ExecuteReader();

    if (r.Read()) //ensure if it is read only once, else modify your `WHERE` clause accordingly
    {
        var s = (Guid)r[0];
    }
    //or even (Guid)cmd.ExecuteScalar() would work

Now you can query in update like this:

string query = @"UPDATE session SET logout_time = @LogOutTime 
                        WHERE user_id = @UId AND PK_Id = @SessionId";

try
{
    if (_conn.State != ConnectionState.Open)
        _conn.Open();
    MySqlCommand cmd = new MySqlCommand(query, _conn);
    cmd.Parameters.AddWithValue("@UId", Utility.usr.Id);
    cmd.Parameters.AddWithValue("@SessionId", s.ToByteArray());
    cmd.Parameters.AddWithValue("@LogOutTime", DateTime.Now);
    cmd.ExecuteNonQuery();

Note: Here I have converted the Guid variable s to byte array before querying. This is important, in WHERE clause, be it UPDATE or SELECT statements in query. I would ask you to move to binary field in MySQL table from varbinary.

Edit: If your table would grow dramatically large then inserting and selecting is a bad idea since SELECT query is an additional query being run. In that case @PinnyM's choice is better. I really do not think MySQL or any other database would have a default way to give back "custom" inserted ids which are not something database generated. So in short I advice you to not go for this..

Edit2: See this answer for getting binary value to .NET datatype. Sometimes casting do not work depending on MySQL .NET connector version..



回答2:

You can use the Guid type which is the MS implementation of UUID. You should be aware that when inserting data into the DB, you may need to convert the Guid to ByteArray if the MySQL driver isn't familiar with handling Guid's. See Store GUID in MySQL from C# for an example of this.



回答3:

You could have also done this using an out parameter from your sproc. See NerfAnvil's reply:

How to get OUT parameter from MySQL stored procedure for an almost exact example.

cmd.Parameters["outnextnoteid"].Direction = ParameterDirection.Output;

...

nextNoteId = (int)cmd.Parameters["outnextnoteid"].Value;