How To Return a Record ID from SQL to C# on Insert

  Рет қаралды 12,447

IAmTimCorey

IAmTimCorey

10 ай бұрын

C# and SQL are often used together. But if you are using Dapper to insert records into SQL, how do you get back the ID of the newly-created record? In this video, I will show you how to access that ID, how to return it from SQL, how to create output parameters, and how to capture return values. And we will do all of that in 10 minutes or less.
Full Training Courses: IAmTimCorey.com
Source Code: leadmagnets.app/?Resource=Ret...
Mailing List: signup.iamtimcorey.com/

Пікірлер: 51
@caseyspaulding
@caseyspaulding 10 ай бұрын
Much appreciated! These DBA type videos are super helpful
@IAmTimCorey
@IAmTimCorey 10 ай бұрын
Glad you like them!
@wesleymrwetyana4289
@wesleymrwetyana4289 10 ай бұрын
Love your content Tim big fan indeed.
@IAmTimCorey
@IAmTimCorey 10 ай бұрын
Thank you!
@danielledehart466
@danielledehart466 10 ай бұрын
I can't thank you enough for these 10 minute videos!
@IAmTimCorey
@IAmTimCorey 10 ай бұрын
Glad you like them!
@andergarcia1115
@andergarcia1115 10 ай бұрын
god bless you master, infinitely grateful for your work.
@IAmTimCorey
@IAmTimCorey 10 ай бұрын
Thank you!
@pavfrang
@pavfrang 10 ай бұрын
Thank you Tim for the great video! I suspect that returning the ID is one of the reasons that GUID is preferred nowadays instead: you can create them and know their value, before calling the insert procedure..
@webdeveloperninja9220
@webdeveloperninja9220 10 ай бұрын
GUIDs are great until you get fragmentation problems with millions of rows. I use GUIDS most of the time but have to rebuild the index every once and a while
@DeeArr
@DeeArr 10 ай бұрын
Why would you do that? If you want a GUID then use newid() or newsequentialid as a default in the table definition and return it as a string output parameter. The OUTPUT clause in the insert or merge statement will return it for you.
@webdeveloperninja9220
@webdeveloperninja9220 10 ай бұрын
If you are using DDD it is nice for the application to create the id.
@pavfrang
@pavfrang 10 ай бұрын
@@DeeArr it depends on what you want to do. For a single record, the newid() is ok, BUT if you want to insert some thousand records, then what is the point of returning all the new ids? It's more practical to have them outside and just insert them. The only need for having the value outside, is when you want to add some thousand child records that use all these ids. It's much faster, if you just generate them outside and use them for the child records as well, than messing up with return statements.
@DeeArr
@DeeArr 10 ай бұрын
@pavfrang My basic example was for a single row update or insert. however, the only true source of the ids is sql server itself. BTW, Not everyone loves guids. A merge statement will give you a dataset of inserted and/or updated ids and it's atomic. Let Sql Server do the work. Unfortunately not many sql devs understand/trust the power of the merge statement.
@torrvic1156
@torrvic1156 8 ай бұрын
I really like not just the video itself but the comments section. One can get so many useful considerations from there also.
@IAmTimCorey
@IAmTimCorey 8 ай бұрын
I am glad they are helpful.
@rajeshprosad6016
@rajeshprosad6016 8 ай бұрын
I like your teaching style.
@IAmTimCorey
@IAmTimCorey 8 ай бұрын
I'm glad.
@rikudouensof
@rikudouensof 10 ай бұрын
Thanks for the video
@IAmTimCorey
@IAmTimCorey 10 ай бұрын
You are welcome.
@ChadiHD112
@ChadiHD112 9 ай бұрын
Amazing tutorial Tim as always. However, I have a question about why you had to specify the @id in the DynamicParameters as Output direction and then add a new parameter as @output and specify it as ReturnValue? Isn't it better to just remove the "@output" and get the value from "@id" directly?
@conbag5736
@conbag5736 10 ай бұрын
I always like watching these short-form videos from Tim. Great work as always. The method you've shown is definitely valid, but in this situation, I prefer to keep things simple: var sql = "INSERT INTO People (FirstName) VALUES (@FirstName); SELECT SCOPE_IDENTITY();" person.Id = await connection.ExecuteScalarAsync(sql, person); This way, I don't end up with zillions of stored procedures for every CRUD operation, and I don't have to do the context-switch between SQL-world and C-Sharp world where I have to confirm the SP name, and the names and types of my input & output parameters. Admittedly, the experience of typing out SQL and/or formatting the query inside a string variable in C# isn't great, but I still think it's a worthy trade off.
@IAmTimCorey
@IAmTimCorey 10 ай бұрын
Well, there are a few things to consider here. The first one is that you are making raw SQL calls from C#. That's not great because it makes it harder for yourself when you try to track down issues from the SQL side. Instead of having a name of a procedure to go to, you have just a raw SQL statement. That means you cannot optimize it on the SQL side - you need to figure out who called it, from where, and then modify that source code. Also, you are making it tougher on SQL to optimize that query. SQL can usually handle it, but not always. Finally, and the biggest issue, is that you are no longer making a call inside of a scope. You are making two separate calls, even though they are "together". That means that "Scope_Identity" isn't actually guaranteed to give you the ID you just created. There is a chance, and it isn't big but it is possible, that you could get the ID of a different record that was recently created (from any table). You wouldn't know until you tried to use the ID and found it invalid. Even worse, you might get back a valid ID, just not the ID of the record you just inserted. You see, a stored procedure is a transaction. That means that the scope is the procedure. Everything inside of it is inside that scope. Therefore, the Scope_Identity returns the most recent ID from that scope so you are guaranteed to get the correct ID.
@conbag5736
@conbag5736 10 ай бұрын
@@IAmTimCorey Great resposne, Tim. Thanks. I have been using this pattern pretty extensively, and I have never witnessed Scope_Identity() give me the incorrect Id - I did some more reading on this and I'm confident that the two statements will be executed in one 'batch' and therefore one 'scope' - assuming there are no triggers or anything messing with the scope context. I take your point about the query optimization - I tend to make a lot of in-line functions or stored procedures whenever I'm doing anything a bit more complex.
@arnotek
@arnotek 9 ай бұрын
Another consideration is that by using stored procedures, you hide the internal implementation of the database. If the case arises that you need another interface to the database, it is straight forward where multiple interfaces use the same stored procedures. SP such as addPerson, etc. where the name of the stored procedure indicates what it does. In this case, the SP can return the ID of the record just inserted. There is also the security issue. SPs can be in different schemas and you can prevent outside applications from directly accessing the underlying database tables which opens a security hole that you can drive a truck through. Also, if you have a team of developers, one segment of the team can be working on the application and another segment on the database. By having a defined interface to the database makes development, debugging, and maintenance much easier. Additionally, if you have a change to the database structure, it is hidden from the application and the application does not need to be redeployed. The list goes on. On a closing note, I had the unique opportunity to write the same application both ways - one with the SQL in the application code and another version that used stored procedures. (I used to put the SQL in the application since the team was well versed in both SQL and C#.) After that experience, hands down, using stored procedures instead of putting the SQL in the application was by far the better approach for a multitude of reasons.@@IAmTimCorey
@cissemy
@cissemy 10 ай бұрын
Thanks Tim How to take in consideration parameterDirection in the generic : SaveData(string storedProcedure, T parameters) ?
@IAmTimCorey
@IAmTimCorey 10 ай бұрын
You can't. You need to use the specific type for that, not the generic T.
@DeeArr
@DeeArr 10 ай бұрын
I have a pretty generic proc that takes a nullable id parameter along with other specific parameters and, if an id is not specified, it performs an insert. If it is, it does an update, all with a merge statement that provides the identity back as an output parameter.
@IAmTimCorey
@IAmTimCorey 10 ай бұрын
Just be careful - the merge statement has a LOT of issues that can burn you. I know quite a few SQL DBAs that have gone away from using merge because of the issues.
@dennisvandermeer8238
@dennisvandermeer8238 10 ай бұрын
What would be the reason for using stored procedures instead of just writing the insert statement in the code? I always put everything in the code as there is more likely more logic in the code that will not end up in a stored procedure and I would rather have everything at one place rather then split up into 2 places. Besides, having stored procedures would make migrating to a different database more complex as syntax might be different
@musicman6294
@musicman6294 10 ай бұрын
I view this as a separation of concerns strategy; let the DB and the application do what they're designed to do. When I design an application, I put a lot of thought into the exact dataset needed to accomplish a task. Once I've got that squared away, I write a stored procedure to give me that dataset. This way, you aren't writing SQL in your C#, just manipulating what the DB gives you. Another consideration is that you can create a service account that can only execute stored procedures and cannot do anything else. Just my two cents...
@pavfrang
@pavfrang 10 ай бұрын
Security and authorization. You block all queries and you leave only some roles to access some procedures. If you ever deal with security in your database, you will realize that this is the safest approach.
@IAmTimCorey
@IAmTimCorey 10 ай бұрын
Well, there are a few things to consider here. The first one is that you are making raw SQL calls from C# is not great because it makes it harder for yourself when you try to track down issues from the SQL side. Instead of having a name of a procedure to go to, you have just a raw SQL statement. That means you cannot optimize it on the SQL side - you need to figure out who called it, from where, and then modify that source code. Also, you are making it tougher on SQL to optimize that query. SQL can usually handle it, but not always. Finally, and the biggest issue, is that you are no longer making a call inside of a scope. You are making two separate calls then to get the "Scope_Identity", but it isn't actually guaranteed to give you the ID you just created. There is a chance, and it isn't big but it is possible, that you could get the ID of a different record that was recently created (from any table). You wouldn't know until you tried to use the ID and found it invalid. Even worse, you might get back a valid ID, just not the ID of the record you just inserted. You see, a stored procedure is a transaction. That means that the scope is the procedure. Everything inside of it is inside that scope. Therefore, the Scope_Identity returns the most recent ID from that scope so you are guaranteed to get the correct ID. Don't try to put your database code inside your C# application in order to put your code in one place. They are different systems and you need to treat them differently or you will get burned. Use SSDT to create your database inside of Visual Studio so you can put your stored procedures in source control if you want, but don't put SQL code in C# if you can help it.
@chrisjohansson9971
@chrisjohansson9971 10 ай бұрын
I usually use connection.InsertAsync(model); without stored procs and does the return quite easily. But yes I see your demonstrating using stored procs.
@conbag5736
@conbag5736 10 ай бұрын
Valid, but keep in mind that InsertAsync isn't vanilla "Dapper" - this comes from one of the Extensions like Dapper.Contrib or something.
@IAmTimCorey
@IAmTimCorey 10 ай бұрын
I find that those things sound good and they work well at first and in small applications, but that they end up being less useful when you get into a more real-world type application.
@sirus49
@sirus49 10 ай бұрын
Why does it matter vanilla or not? You use what you need.
@chrisjohansson9971
@chrisjohansson9971 10 ай бұрын
@@IAmTimCorey might need to expand on that answer with "less useful". I have written some "real world" applications using this model with generics and it works just fine
@kevingates5851
@kevingates5851 10 ай бұрын
Tim, why not just “SELECT SCOPEDIDENTITY()”, and have your dapper expect an int / GUID as a result of the query? Is that bad practice?
@IAmTimCorey
@IAmTimCorey 10 ай бұрын
Some people do that. The only issue is that some people return an int that represents the number of records affected. They could assume that the returned value was the number of records rather than the ID. Conversely, if you expect it to be an ID and it is the number of records, you also will have the wrong value.
@kevingates5851
@kevingates5851 10 ай бұрын
Wouldn’t “SELECT” and RETURN be two different things thought? Sorry if I am misunderstanding you. I thought return is normally a code or status (could be records affected) whereas SELECT would be the result of your query - in this case the new identity.
@IAmTimCorey
@IAmTimCorey 10 ай бұрын
Sorry, I was thinking you were returning that value as a return. Yes, if you did a select then you would return that value as a record. That is definitely a valid option.
@JohnPeter-yf5jf
@JohnPeter-yf5jf 10 ай бұрын
Good video topic!
@IAmTimCorey
@IAmTimCorey 10 ай бұрын
Thanks!
@fideis86
@fideis86 10 ай бұрын
Insert into target-table (columns-to-insert) Output (columns-inserted) into (table-variable) Select/values clausule
@dmitrybelov5703
@dmitrybelov5703 10 ай бұрын
I prefer this because of possible using of sequencies when inserting new values
Fluent Assertions in Unit Testing in C#
10:09
IAmTimCorey
Рет қаралды 10 М.
How to connect C# to SQL (the easy way)
1:20:40
IAmTimCorey
Рет қаралды 1 МЛН
Как быстро замутить ЭлектроСамокат
00:59
ЖЕЛЕЗНЫЙ КОРОЛЬ
Рет қаралды 6 МЛН
小路飞姐姐居然让路飞小路飞都消失了#海贼王  #路飞
00:47
路飞与唐舞桐
Рет қаралды 94 МЛН
10 C# Libraries To Save You Time And Energy
33:59
IAmTimCorey
Рет қаралды 203 М.
Intro to the CsvHelper Library for C#
27:12
IAmTimCorey
Рет қаралды 23 М.
5 Signs of an Inexperienced Self-Taught Developer (and how to fix)
8:40
Intro to Records in C# 9 - How To Use Records And When To Use Them
1:19:44
Learn SQL In 60 Minutes
56:24
Web Dev Simplified
Рет қаралды 2 МЛН
MS SQL tutorial showing how to return the latest record from a table
8:07
Accessible IT Software Tutorials
Рет қаралды 11 М.
SQL Database App with Windows GUI - Project Tutorial
3:10:25
freeCodeCamp.org
Рет қаралды 114 М.