SQL Transactions in C# using Dapper - A TimCo Retail Manager Video

แชร์
ฝัง
  • เผยแพร่เมื่อ 24 พ.ย. 2024

ความคิดเห็น • 149

  • @timothywestern6488
    @timothywestern6488 5 ปีที่แล้ว +7

    I'm really thankful for this example, I had a job a few years ago where I had to clean up a lot of these failures to close etc. And I learned this exact pattern as a way to solve that leak issue. This is perhaps the best and most succinct explanation of it I've seen in 10 years. Well done, Tim.

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว +2

      I appreciate the kind words.

  • @harag9
    @harag9 5 ปีที่แล้ว +14

    Great video again Tim, I know there is another "bug fix" video after this so what I'm about to say you might have fixed in there. Just a couple of issues I spotted:
    1. When you commit the transaction you also close the connection, this leads to an error in your using statement on the dispose, the error basically tells you that you don't have a transaction open so there is nothing to commit again. - not sure why your code doesn't stop on the lines when it throws an error (maybe an option I have turned on).
    2. I would suggest NOT to close the connection when you commit the transaction - the commitTransaction() method should do one thing. commit. I would have the close connection on the dispose only. This way the user (developer) can open & close several transaction within the using statement. (hope this makes sense).

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว +11

      Yep, I fixed issue 1 in the follow-up video. As for not closing the connection, interesting idea. However, I would rather have the person explicitly open a new connection when they needed it again rather than risk having a long-running connection open to my database. Opening a connection isn't a big deal performance-wise. Leaving one open is a big deal.

    • @faraz-online
      @faraz-online 4 ปีที่แล้ว +1

      Yep! The transaction seems to be tried twice although failing the second time. Definitely a great debugging exercise for learning quite a lot like finding the Dispose procedure being hit under any condition despite of not being not explicitly referred to! Thanks again for the Treasure Tim! Can't wait to start the next video!

    • @efimov90
      @efimov90 4 ปีที่แล้ว +1

      You can fix it by checking _connection.State equals to ConnectionState.Closed before CommitTransaction at Dispose.

  • @ranaislam2921
    @ranaislam2921 5 ปีที่แล้ว +3

    Tim Corey you are the best tutor. You make very effective series for the beginners and also for them who can not afford to buy online course. i am big fan of you And learn a lots from your tutorial

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว +1

      I appreciate the kind words.

    • @ranaislam2921
      @ranaislam2921 5 ปีที่แล้ว

      Hey Tim will you ever make a series of MVC Project

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว +1

      MVC is coming to this project soon.

    • @ranaislam2921
      @ranaislam2921 5 ปีที่แล้ว

      @@IAmTimCorey thanks

  • @allanmaynard576
    @allanmaynard576 3 ปีที่แล้ว

    Awesome video, I immediately became a Patreon, your videos are as valuable as college lectures... Thank You !

  • @dotnetenthousiast1855
    @dotnetenthousiast1855 3 ปีที่แล้ว

    Wonderful implementation, I was just scrolling trough your video's in seach for yet another useful video and you didn't disapoint. Transactions are important guys 'm kay.

    • @IAmTimCorey
      @IAmTimCorey  3 ปีที่แล้ว

      Glad it was helpful!

  • @greg1486
    @greg1486 3 ปีที่แล้ว +1

    This course is awesome Tim and it has been so helpful to me. Thank you so much for making these!

    • @IAmTimCorey
      @IAmTimCorey  3 ปีที่แล้ว

      You're very welcome!

  • @nitrorulezzz
    @nitrorulezzz 4 ปีที่แล้ว +1

    One small tip: Instead of adding a temporary variable to look at the exception, when you are in the catch block with the debugger, you can look in the locals window to the variable $exception.

  • @marekott4432
    @marekott4432 5 ปีที่แล้ว

    Thanks for this course, Tim. It's really great that your share knowledge like this on YT.

  • @Vitalick15
    @Vitalick15 2 ปีที่แล้ว +1

    When someone asked me who was my teacher, I told them, Tim Corey)

  • @LordShpinaq
    @LordShpinaq 4 ปีที่แล้ว +1

    What I usually use to rename stuff like property names or method names is crtl+r+r key combination, which also renames pretty much everything including fields in interfaces. Never had any problems with it even in kinda complex solution I'm working on in my workplace so I recommend it to everyone here :)

  • @benedictpardo6366
    @benedictpardo6366 5 ปีที่แล้ว +2

    Hi Tim, suggestion here. I think adding the functionality of entering an amount after checking out, for displaying the change is part of a basic register too.

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว +2

      I've debated how I would go about that. We don't really have a "check out" screen where they enter cash/credit and the amount. Have to think that one through to see if it is necessary for version 1. Right now, it is up to the cashier to indicate that they got paid, whether they use a totally separate credit card machine or a cash drawer and made change manually.

    • @benedictpardo6366
      @benedictpardo6366 5 ปีที่แล้ว

      No problem Tim. I just thought that it's a better experience if the system had that feature.
      Anyways, thank you so much for this tutorials. I learned a lot of things from this series and will learn a lot more. You're the best!

  • @markharwood6794
    @markharwood6794 2 ปีที่แล้ว +2

    Do you ever use Unit of Work and have a transaction distributed over multiple repositories? I use aggregates a lot and keep messing with the pattern I use and would be very interested to hear your take on that

  • @LarryB15
    @LarryB15 4 ปีที่แล้ว

    I am really liking this series. Being out of work during Covid has given me the opportunity to investigate a number of technologies I have not used before.
    One suggestion though, would it be better to create a second SQLDataAccess class specifically for transactions to avoid the possibility of SaveData(...) being called mid transaction..

  • @Otonium
    @Otonium 5 ปีที่แล้ว

    Thanks! Dapper is being used more and more in the industry.

  • @runtimeterror4027
    @runtimeterror4027 4 ปีที่แล้ว

    This playlist is truly a life Saver I’ve been following your content for some time and it’s just amazing. I’m trying to implement tab control using the caliburn micro I’m running through some issues do have any course on that?

  • @99MrX99
    @99MrX99 5 ปีที่แล้ว +3

    Hi Tim, it does not clear out the cart for you, because for you the same thing happens as for me and what RC mentioned in the comment. When you try to commit the transaction the second time (through Dispose), it gives an exception telling it is already commited. For me the debugger breaked at the exception but it seems like because of your exception settings it did not break, that's why you didn't notice it.

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว +2

      Good catch. I'll probably do a video on that this week. The fix is fairly simple.

  • @muhammadraza5108
    @muhammadraza5108 9 หลายเดือนก่อน

    Hi Tim Thanks for this example, pretty good. One thing in running mode if transaction is rolled back how user will know that my data is not recorded. can we provide any message at this state?
    Regards

    • @IAmTimCorey
      @IAmTimCorey  9 หลายเดือนก่อน

      At 35:08 on line 80, we roll back the transaction in the catch but then continue the exception (the throw). That will allow us to handle the exception in the UI, allowing the user to know there was a problem with saving the data.

  • @piotrc966
    @piotrc966 5 ปีที่แล้ว +1

    Tim, I used for transaction System.Transactions class:
    using (var transactionScope = new TransactionScope())
    {
    SqlDataAccess sql = new SqlDataAccess();
    ....... save //sale
    ....... save //sale detail
    transactionScope.Complete();
    }
    This is bad or worse then your manner?
    I checked and I throw exception after first save, all is rollback, so it works.

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว +1

      I didn't want to move my transaction code into the next layer up. I wanted the data access class to handle that.

    • @piotrc966
      @piotrc966 5 ปีที่แล้ว +1

      OK, right. You right. Better keeps this kind of code lower for better separation and more flexible code.
      Thank you.

  • @islam-nuggets
    @islam-nuggets 5 ปีที่แล้ว

    Thanks Tim, you are the best!

  • @siddgoen
    @siddgoen 3 ปีที่แล้ว

    Nice video again. I implemented the transaction mechanism using SQL transaction in the stored procedure. I used TVP to pass the sale details to the stored procedure. If anyone is interested to know the details, please let me know.

  • @AbubakrMahdiSan
    @AbubakrMahdiSan 5 ปีที่แล้ว

    Hi Tim , I am huge fan of you , Thank you very much.

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว

      You are most welcome. Thanks for watching.

  • @dotnetdevni
    @dotnetdevni 5 ปีที่แล้ว

    I have changed to dapper now it’s great dapper dapper plus and dapper contrib. Amazing utils that helps with the short comings of entity framework.

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว

      I am glad you are enjoying it.

    • @dotnetdevni
      @dotnetdevni 5 ปีที่แล้ว

      IAmTimCorey I have used it a few years now was excited when they said efcore would get server side filtering but that it would not be coming to winforms core i don’t get why not

  • @brianwells990
    @brianwells990 4 ปีที่แล้ว

    Hi Tim, Thanks for all the videos you put out! A question (that maybe has no right or easy answer) is, how far "out of the mainstream recommendation" is it to encapsulate "a fair bit of logic" in stored procedures? I see you've done it here, and this is definitely the route I chose, but I have a few peers who keep reminding me that this is "Doing It Wrong(TM)" and that the API should handle the business logic. The book I'm using as guide (to use PostreSQL sprocs) was written by a founder of Skype. That approach worked well (until MS bought it!) so it seems to me that sprocs, done carefully, can work swimmingly. But I always feel I'm breaking industry standards in doing so. Your thoughts appreciated, as you have more interaction with other experts.

    • @IAmTimCorey
      @IAmTimCorey  4 ปีที่แล้ว +1

      My philosophy is to let SQL do what it does best and let C# do what it does best. That means I let SQL look up data, sort data, filter data, and even protect data. Then I let C# break the data apart, work on it, etc. That means I don't put a TON of logic in my stored procedures but I also am ok with some.

    • @brianwells990
      @brianwells990 4 ปีที่แล้ว

      @@IAmTimCorey thx for your thoughts! I found myself slipping down the slope when I realized that editing the data and giving good FK constraint violation feedback ("here's why I couldn't save your record") led me to the point where I felt the db was faster in-and-out doing all those checks and saving than having the API do a pile of calls to validate fields prior to save.

    • @markharwood6794
      @markharwood6794 2 ปีที่แล้ว

      I have recently had to change out an Oracle DB to a Postgresql DB for an application for one of the large pharma companies and believe me you want AS LITTLE logic as possible in your DB :)

  • @joannagechanfon4770
    @joannagechanfon4770 ปีที่แล้ว

    First of all, I want to say thank you for sharing all your videos, I am learning so much with your courses. I want to ask you a question, My class sqlDataAccess implements the interface IsqlDataAccess, and for that reason, the constructor of the class sqlDataAccess initializes the object ISqlDataAccess
    public SqlData(ISqlDataAccess db)
    {
    this.db = db;
    }
    for that reason, I can't use the statement using(sqlDataAccess db = new sqlDataAccess()) inside my methods, and I don't know how to do it, please, I appreciate any help.

    • @IAmTimCorey
      @IAmTimCorey  ปีที่แล้ว

      Change the name of one of your "db" objects. They are two different things.

  • @aakashbista2290
    @aakashbista2290 3 ปีที่แล้ว

    Can you show how we can execute store procedure with multiple join with dapper and populate the model.
    Thanks

    • @IAmTimCorey
      @IAmTimCorey  3 ปีที่แล้ว

      From the Dapper side of things, it is no different than a normal query - you return a set of data. You just need a model that matches that set. From the SQL side, you just need to know how to properly do joins. That I covered some in the Tournament Tracker project as well as in my SQL Databases from Start to Finish course on iamtimcorey.com

  • @pilotboba
    @pilotboba 5 ปีที่แล้ว

    I would suggest that your dispose does a Rollback if the transaction hadn't been committed. ie, explicit commit, implicit rollback.
    You could also start the transaction implicitly since you have separate SaveWithTransaction methods.
    Also, not too familiar with dapper, but adding the rows in a loop is making a call to sql in every iteration. Is it not possible to push the list (batch insert) with Dapper somehow other than using the table value param?

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว +1

      I am following the typical pattern for using statements, which is why it commits by default. I debated on that a bit but in the end, I defaulted to what is probably the assumption. As for starting it with the SaveWithTransaction method, that wouldn't work well since the LoadWithTransaction method might be called first. As for Dapper making each call one by one, that is how all data access/ORMs make calls to stored procedures unless, as you pointed out, we used a TVP. In theory you could call an insert with many values attached but that wouldn't save you anything really.

    • @pilotboba
      @pilotboba 5 ปีที่แล้ว

      @@IAmTimCorey I was comparing to the TransactionScope which will rollback if you don't explicitly call Complete. Which makes sense... assuming an error occurs in your using..... saves you from having to do a try...catch at that level.
      But, to each his own.

  • @tomzipl
    @tomzipl 5 ปีที่แล้ว +1

    Hi Tim, can't you just wrap the code in "using (TransactionScope scope = new TransactionScope())" block?

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว

      We could but then that brings data access code into the business logic.

  • @kengthe5949
    @kengthe5949 3 ปีที่แล้ว

    thank you for your efforts! Nice video :).

  • @KunalMukherjee3701
    @KunalMukherjee3701 3 ปีที่แล้ว

    One question, Can't we inject sqlconnection instead of wrapping it in a using block everytime, what are the pros and cons of this approach

  • @rc2893
    @rc2893 5 ปีที่แล้ว +5

    Hi Tim, when I ran this after adding the transaction code. I got an error saying it was already commited. This is due to the explicit then implicit call to CommitTransaction. I fixed this by setting _transaction and _connection to null after the commit and close calls.

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว

      Interesting. Did you use the question mark after the item name?

    • @rc2893
      @rc2893 5 ปีที่แล้ว

      @@IAmTimCorey Yes I did.

    • @eofjjeifj4z38973498
      @eofjjeifj4z38973498 5 ปีที่แล้ว

      I had the same problem

    • @StefanJarina
      @StefanJarina 5 ปีที่แล้ว

      @@IAmTimCorey Just to add here, I just had the exact same problem following the video to the point... I think the issue here is, that _transaction is actually never null and "?" is checking for that object to be null and as far as I can see only the properties of _transaction object are "nulled"... Solved it for now by explicitly setting _transaction to null after commit:
      public void CommitTransaction()
      {
      _transaction?.Commit();
      _transaction = null;
      _connection?.Close();
      }

    • @StefanJarina
      @StefanJarina 5 ปีที่แล้ว

      @@IAmTimCorey Nevermind :-) I see you fixed it in next video. Great job and thanks!

  • @katievenable3608
    @katievenable3608 4 ปีที่แล้ว

    Thank you Tim

  • @Sm123bg
    @Sm123bg ปีที่แล้ว

    I noticed that all of your methods in SqlDataAccess are all synchronous. Are asynchronous methods ok to use with transactions?

  • @mdotlic
    @mdotlic 3 ปีที่แล้ว

    Hi Tim. Thanks for all of the videos, you're a great teacher!
    I have a question and hope you or someone else who sees this can help. I have a transaction that's in a stored procedure in the ms sql server (not in c#). I call it from c# and it works perfectly, but I can't figure out how to get a notification in case of a rollback. It does its thing in the sql server and I can see the result in case if commits (both in c# and sql server), but I have no idea how to get a message box if it rolls back.

    • @mdotlic
      @mdotlic 3 ปีที่แล้ว

      Never mind, found the answer in your next video 😄. Thanks again, you're a lifesaver!

    • @tomthelestaff-iamtimcorey7597
      @tomthelestaff-iamtimcorey7597 3 ปีที่แล้ว +1

      Thanks for sticking with the series!

  • @pradm777
    @pradm777 2 ปีที่แล้ว

    Thank you very much .

  • @bluescanfly1981
    @bluescanfly1981 5 ปีที่แล้ว

    What would you say about having StartTransaction accept a lambda / delegate that would basically setup the connection start transaction and pass the transaction ref to the lambda ? After the lambda is done we could clean up in StartTransaction - i am thinking template method pattern / aspect oriented programming - that way the actual load / save wouldn't need to worry about clean up, and we should be able to limit code duplication for setup . Also can we use JSON instead of TVP? I am a noob when it comes to T-SQL. I've not used C# for a decade, but with .NET Core and your wonderful content, i am considering it for a couple projects. Thank you so much.

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว

      Good questions. I would have to map it out to see exactly what you mean (having a hard time visualizing) but the big thing for me is that we don't bubble up data access code into higher layers. I don't want anything caring about database "stuff" beyond the bottom layer. Even telling it to open a transaction is pushing it for me. As for passing JSON, that would be a performance issue and it is something that only more modern versions of SQL even support.

  • @djangounchained7314
    @djangounchained7314 4 ปีที่แล้ว

    While Corona is around ... I will keep learning ...

    • @IAmTimCorey
      @IAmTimCorey  4 ปีที่แล้ว

      It would be good to keep going after as well.

  • @ZnSstr
    @ZnSstr 5 ปีที่แล้ว

    Hey Tim, I had recently an interview where I didn't had enough experience anyways and they asked me about garbage collector and dispose method and what happens behind the scenes, can you make something similar by your hand or just address the subject? I tried to explain on my own junior terms but they didn't liked it, I think they wanted some deep answer only a professional would know. I can google it, but I think you can make it easier to understand :) Also Happy Hollidays.

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว +1

      I can add that suggestion to the list. In general, Dispose safely closes out a resource. Each method that implements IDisposable determines what shutdown tasks need to go in the Dispose method. That method gets called either manually or when the object is instantiated as part of a using statement and that using statement concludes. The garbage collector cleans up any memory that is no longer needed when the system needs memory. It cleans out unused variables and references when they go out of scope. However, it isn't an instantaneous thing. The GC does its work when it determines the system needs the memory.

    • @ZnSstr
      @ZnSstr 5 ปีที่แล้ว

      @@IAmTimCorey Yea I used the "using" and the interface IDisposable example and I said something like, they are freeing the memory, and he asked how does that happen and I didn't know what to say, he said I only know how to use them but I don't understand the process and I should learn more, maybe he wanted to see if I know how to create an IDisposable mysef or at least the logic from scratch. Or maybe is just what you said but I didn't used the proper language since I am unexperienced. Thank you for reading the comment and give your expertise, means a lot :) Real teacher that can handle hundrents of comments when a real teacher can't handle 15 people in a class.

  • @georgevlassis8319
    @georgevlassis8319 4 ปีที่แล้ว

    I am not sure if this is the appropriate video to ask this question., but are you using the repository pattern for data access in the TimCo series? Is it easy to switch from Dapper to another ORM?

    • @IAmTimCorey
      @IAmTimCorey  3 ปีที่แล้ว +1

      Yes, the data is all wrapped in an abstraction so that it can be replaced with a different data access layer if you wanted.

  • @minamishail_Tech2024
    @minamishail_Tech2024 5 ปีที่แล้ว +1

    How to protect DB .MDF & .LDF files from re-attache to another computer server or getting open by my client's to prevent checking DB tables, schema or any other objects ?

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว +1

      You apply database security at least, and maybe encryption at rest.

  • @alexandrunuta4284
    @alexandrunuta4284 4 ปีที่แล้ว

    Hi Tim,
    I'm not sure I understand the reason behind using transactions in c#, maybe you can help me with that
    I understand that we don't use TVP because the inserts would be small for this application in the real world, but
    why is that a reason to not use transactions inside the procedure? even with the current parameters (not TVP) we could still use transaction in SP
    It feels like TVP and SP vs C# transactions are 2 unrelated issues or there's something I don't get.
    Also, the few articles i found regarding this (pros/cons about using it in c# or in sp) mentioned the use of distributed transactions when multiple data sources are used at once, but for single database use, transactions are better used in sql
    Thank you

    • @IAmTimCorey
      @IAmTimCorey  4 ปีที่แล้ว +1

      The data is coming from C# so there is a second data source. The user is the second data source (they create the order). The reason why we use a transaction is because we have one parent record (the order) and then multiple child records (the order details). So, the only way to send all of that data to one stored procedure would be to create a TVP. Otherwise, we have to call the order detail stored procedure multiple times to enter all of the rows. That is why we use a transaction. We can send the order information (the summary) and insert each detail record. If anything were to happen halfway through, we would want to roll back. The transaction in C# code will allow us to do that.

  • @parapadirapa
    @parapadirapa 4 ปีที่แล้ว

    Tim is a great lecturer, and this may be off track because I watched this single video from the series, but if the theme is Dapper, he should only speak about Dapper. I lost 10min in the beginning just looking at VCS explanations. SRP, Tim... Despite that, great lectures!

    • @IAmTimCorey
      @IAmTimCorey  4 ปีที่แล้ว +1

      Yeah, this is a video in a series, not an individual tutorial. The goal isn't to teach Dapper. I do that here th-cam.com/video/Et2khGnrIqc/w-d-xo.html and here th-cam.com/video/eKkh5Xm0OlU/w-d-xo.html Instead, this is on how to implement Dapper into our application design (and actually quite a bit more). What we are doing is building a complete application using the knowledge we already have. Basically, think of this series as implementing what we know. Now I do work hard to show context around anything I teach, though. The reason is that just watching an isolated tutorial is not good enough. You will have a hard time putting that isolated piece into the "real world" since it has to connect to real things. That's what I teach: how to connect it, what the best practices are, what pitfalls to avoid, etc.

  • @ranielgarcia8685
    @ranielgarcia8685 4 ปีที่แล้ว +1

    Hi Tim,
    Thank you so much for this series of videos, it helps me to improve my C# programming skills.
    I just have this issue
    I remove the sql.CommitTransaction(); at the bottom of the foreach (var item in details) because when using statement call the Dispose method it throws an error (This sqltransaction has completed; it is no longer usable), it that ok?

    • @ranielgarcia8685
      @ranielgarcia8685 4 ปีที่แล้ว

      I see the solution on the next video :D

    • @IAmTimCorey
      @IAmTimCorey  4 ปีที่แล้ว

      Great! Glad you found it.

    • @DrowninGGaming
      @DrowninGGaming 2 ปีที่แล้ว

      @@ranielgarcia8685 Thank you friend, glad I wasn't the only one with this issue haha!

  • @munkhn73
    @munkhn73 5 ปีที่แล้ว

    Good morning?
    I have some questions.
    1. using () { ... } means whatever object created in the bracket calls its Dispose() at the end of curly brace? Just that? Or everything that are created in the using curly braces are disposed? What if I create object that doesn’t implemented IDisposable? What i understand is a=b where
    a. using(var someObj = new SomeClass()
    { ... }
    b. var someObj = new SomeClass();
    ...
    someObj.Dispose();
    2. Does transaction.Commit(); destroy the transaction object at the end of method? Same with the connection. I don’t need to do something like transaction=null, connection=null?
    3. You called transaction.Commit() implicitly and explicitly. Doesn’t that affect your application or database? IMO you’d do like this(below) because you already called commit explicitly and explained reason why you are doing that.
    Dispose() {
    _transaction.Close(); // if it has Close method. Or whatever method that will closes the transaction.
    _transaction=null;
    _connection.Close();
    _connection=null;
    }
    Calling commit on the dispose looks unconfortable. Setting nulls depends on the answer of second question.

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว +1

      For question 1, using is a bit better because it calls that dispose even if the code crashes. For 2 and 3, I'll be doing a bug fix video on Friday (hopefully) that will clarify that a bit. We need to set the object to null and close it only once.

  • @andywalter7426
    @andywalter7426 5 ปีที่แล้ว

    I have a question. You said a person should not do most transactions in c#. However, i'm not sure how else a person can do transactions without c#. I've done database development for many years and I always did transactions directly in vb.net before i learned c#.

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว

      You would do the transaction in SQL itself. That is the preferred method.

  • @erikvolger5631
    @erikvolger5631 3 ปีที่แล้ว

    I did not see my solution in the comments so I'll share it here for everyone who is interested:
    The SqlDataAccess class is doing two things now: isolated acces and transactions. So I created and used the SqlDataAccessTransaction class which only handles transactions. I start the transaction in the constructor, and commit in the Dispose method, so you don't have to do that explicitly.
    Another thing I changed is that I pass the connectionStringName in the constructor and cache the connectionString that I read from config. Then you don't have it to pass it in the Load/Save methods anymore... For this I added a base class for both SqlDataAccessand SqlDataAccessTransaction to hold the connectionString.

  • @CoderboyPB
    @CoderboyPB 4 ปีที่แล้ว

    Hi Tim, I am confused why you did not get that error, which I got:
    In the using Block of SqlDataAccess (in SaleData.cs) you commit at the end the transaction.
    But because of using 'using' syntax at the end Dispose() will be called, where is another commit, which causes an Exception then, because the transaction has already commited ...
    So I deleted the Commit all in the using block and now it works.

    • @CoderboyPB
      @CoderboyPB 4 ปีที่แล้ว

      ok, just saw, that you already talked about that :-)

    • @IAmTimCorey
      @IAmTimCorey  4 ปีที่แล้ว

      I am glad you figured it out.

  • @KurtInTampa
    @KurtInTampa 3 ปีที่แล้ว

    spSale_Insert I have been hung up on this for the past couple of days, cross-referenced other lessons. It has a select @Id (47:48) at the end for the newly inserted Id, later corrected in another video. Maybe could have been: output inserted.Id, it doesn't seem to matter, because it doesn't seem to have been used. Instead another round trip was made to the DB to get it. Can that be done in one Dapper exec call when passing the stored proc the object? Or does it require mapping all the parameters in order to declare Id as output? Thanks...

    • @Swoleasaurus
      @Swoleasaurus 3 ปีที่แล้ว

      You are correct, he didn't use it. You can create a transaction method that returns an integer so it makes the insert and then returns the ID. See below:
      public int SaveDataInTransactionWithOutPut(string storedProcedure, T parameters, string OutputParameterName)
      {
      var parametersNew = new DynamicParameters(parameters);
      int outputID;
      parametersNew.Add($"{OutputParameterName}", dbType: DbType.Int32, direction: ParameterDirection.Output);
      _connection.Execute(storedProcedure, parametersNew,
      commandType: CommandType.StoredProcedure, transaction: _transaction);
      outputID = parametersNew.Get($"{OutputParameterName}");
      return outputID;
      }

  • @cqli7981
    @cqli7981 4 ปีที่แล้ว

    Hi, Tim
    Thank you for the great video. I am thinking to add a register user view to register new user. Then write aspnetusers Id to dbo.user table. Any suggestion?
    Thanks.

    • @IAmTimCorey
      @IAmTimCorey  4 ปีที่แล้ว

      You can definitely do that.

  • @mohamaddjelouah9332
    @mohamaddjelouah9332 5 ปีที่แล้ว

    hi tim i have a question so am using mvvm like u and i have a datagridview i want to implement a search textbox to search from the datagrid so my question is whats the best i can work with or do to get a proper result thank u for helping ur the best

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว +1

      The search box is just another property and then its value should filter your list (which will filter the datagridview).

    • @mohamaddjelouah9332
      @mohamaddjelouah9332 5 ปีที่แล้ว

      @@IAmTimCorey i didnt fully understand are you saying that that the searchbox will filter my bindablecollection ??? thank you

  • @rowanlidbury
    @rowanlidbury 4 ปีที่แล้ว

    I take it your talking about “Ess-Cue-Ell” server? Not a server hosting the next chapter of a famous movie!

    • @IAmTimCorey
      @IAmTimCorey  4 ปีที่แล้ว

      Yep, SQL Server. There are two common pronunciations: Ess Cue Ell and sequel. I use the latter usually.

  • @tauqeerahmad8715
    @tauqeerahmad8715 5 ปีที่แล้ว

    one bug i found here if i add items to the cart and then log out and log in again the cart wont get clear.

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว

      Yep, thanks. A few people spotted that one. We will fix it soon.

  • @MrKillertrance
    @MrKillertrance 5 ปีที่แล้ว

    why not using Linq to Entities or Linq to Sql it can handl all that in one transaction ?

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว +1

      I'm using Dapper here for my data access so I continued to do so. I'm not a big fan of mixing data access methods inside this small an application.

    • @MrKillertrance
      @MrKillertrance 5 ปีที่แล้ว

      @@IAmTimCorey good can y do a video of difference between Dapper and Linq, it will be helpfull thanks for all your videos its a good source of informations and updates in C#

  • @kapkoder4009
    @kapkoder4009 4 ปีที่แล้ว

    Please i need help, can someone point me to a tuturial series to learn how to transfer money? This video is too advanced

    • @IAmTimCorey
      @IAmTimCorey  4 ปีที่แล้ว

      How to transfer money? Using C#? That is going to be complex, since there is a lot of security that needs to surround money transfer.

    • @kapkoder4009
      @kapkoder4009 4 ปีที่แล้ว

      @@IAmTimCorey I took 70h worth of C# courses and used it for about 2000h with Unity engine, now im looking into a way to make a transaction app, i know its going to be hard thats a given
      I just can't seem to find the right tutorials (from start to finish)
      I would love to be able to make the app in Unity engine but I dont think thats possible
      I just need a point in the right direction 😅 and when you linked your 7h course in the video it said the page could not be loaded

  • @SuperDre74
    @SuperDre74 4 ปีที่แล้ว

    Hmmmm.. In regard to the logging off of the user and you wanting to use LoggedInUserModel as a Model, I think it would have been better to have an APIHelper.LogInUser(Emailaddress, Password) which in itself calls the APIHelper.Authenticate and APIHelper.GetUserLoggedInInfo. And remove the UserLoggedInModel.LogOutUser function, and moved the implementation to the APIHelper.LogOutUser so it also clears the user info (persionally I'd rather have it as a separate function APIHelper.ClearUserLoggedInInfo and call it from APIHelper.LogOutUser..
    And in reality I'd rather have the User object handle all that stuff for me, so I only have to call _user.LogIn(EmailAddress, Password) and later _user.LogOut (as I don't need to know anything about how to log in or out, now you have to explicitly use the API Client to do that.
    Also I just now noticed you using inconsistent names, If you use LogIn you should use LogOut, if you use LogOn you should use LogOff.
    And why did "connection = new SqlConnection(connectionString)" work when using "using" as it seems to "Open" it by itself, but not if we instanciate it ourselfs regularly?
    And ofcourse the Commit in the Dispose is a bug, but I think you'll handle it in your next video.
    To be honest, I'd probably would have liked it to see you actually use the SQL transaction way as it is much safer, even for 'simple' stuff..

    • @IAmTimCorey
      @IAmTimCorey  4 ปีที่แล้ว

      That connection opening does work on its own but you don't want to do it that way. Wrapping it in the using just ensures it will be disposed. That's all. As for putting the transaction into SQL instead of C#, to do that we would need to build in some added complexity. We would need to create a TVP in SQL in order to send all of the data over to SQL in one call. That's not ideal, and something I discussed briefly on how I didn't want to add that complexity yet. We can in the future if we want with very little effort.

  • @michaelcollins4075
    @michaelcollins4075 5 ปีที่แล้ว

    Why would you do anything so complicated and you get paid for this too, unbelievable? I must have got you on a good day sometime back.

    • @IAmTimCorey
      @IAmTimCorey  5 ปีที่แล้ว +3

      The real world is complicated. In this particular instance, if you don't do it this way, you might end up with partial data in your database. That isn't ideal. In fact, that could be very bad. So, we added this safety mechanism to ensure we protected our data and our database. It is kind of like saying that putting guardrails along dangerous curves isn't important because cars drive on the road, not off the edge. That is true until there is an accident and then you are glad you spent the time adding in the safety mechanism.

    • @michaelcollins4075
      @michaelcollins4075 5 ปีที่แล้ว

      @@IAmTimCorey I don't think you know what you are doing-especially with database technology. From the basics of table design right thru the shebang. This whole lesson would have been cleaner and so much easier to understand and implement had you wrote it in SQL. You seem to swing from brilliant insight to pure dumb and winging it on others ignorance. What is worse, then you defend yourself with the above. It is not as though implementing stored procedures with transactions is hard.

    • @Jason-Woolf
      @Jason-Woolf 2 ปีที่แล้ว

      @@michaelcollins4075 If you have done a better course of training videos than Tim has then please post a link to your 100 hours+ of free content. I agree there are easier ways to do some things and as programmers we are all stronger or more experienced in some aspects of software engineering than others but on the whole this is by far the best, most comprehensive start-to-finish course on the internet. I guarantee if you posted up a similar amount of your own work and had 30k programmers looking over your shoulder there would be a number of them who could pick holes in your weak areas, so why be rude to someone who has put so much effort into this project, maybe you need to take a course on humility.

  • @MosquitoMurderer
    @MosquitoMurderer 3 ปีที่แล้ว

    Naming is hard.