12

When I call a method that need dbcontext for update or insert but only want one saveChange() like following

Action: Login

        TempDBEntity context = new TempDBEntity();
        var temp = context.Users.Where(m => m.user_unique_id == 1).FirstOrDefault();
        temp.timestamp = new DateTime();
        temp.AddLog("Login");
        context.SaveChanges();

Function: AddLog

public void AddLog(string activity){
        TempDBEntity context2 = new TempDBEntity();
        var log = new UserLog();
        log.user_id = this.user_id;
        log.activity = activity;
        context2.UserLog.Add(log);
        context2.SaveChanges();
 }

As you can see, there is double SaveChanges() which I only need 1 SaveChanges().

Should I pass DBContext as another parameter for AddLog() or should I declare static variable for dbcontextin this case?

Thanks a lot.

Amareesh
  • 368
  • 2
  • 5
  • 19
chaintng
  • 1,325
  • 3
  • 14
  • 26
  • How about just don't call the first savechanges() – jazza1000 Sep 09 '15 at 06:21
  • Not call first savechange? Then it will not be added. – chaintng Sep 09 '15 at 06:23
  • 2
    I think passing context as parameter would be better than declaring it as static variable. – Girish Vadhel Sep 09 '15 at 06:26
  • But in real application, there is a many method that have this conflict. Should i have to pass parameter to all of these method? – chaintng Sep 09 '15 at 06:29
  • Unless the intention is that your site is only ever used by *one* person, a static variable just isn't the right solution. Almost all asp.net websites are expected to be used by *multiple* users at the same time - and you wouldn't want them all to be sharing the *same* context object. – Damien_The_Unbeliever Sep 09 '15 at 06:46
  • Read this: https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=91 and http://stackoverflow.com/a/29808487/261050, and especially the SaveChangesCommandHandlerDecorator class. – Maarten Sep 09 '15 at 06:47

3 Answers3

9

In your case i would create a new dabtase context in the method you need it, because this is the easiest way and you can reuse your methods very good.

This should not make a lot of performance problems, because entity framework cache all important information over the database context, so creating a new one is very fast.

If you want optimize the amount of transactions, than i would write a kind of handler, which implements it's own SaveChanges method and hold one databse context per instance. Than you have one more abstraction layer and a nice API for later use.

Here is a simple example:

class UserLogin
{
    private TempDBEntity dbContex;

    UserLogin()
    {
        // ctor create dbContext
    }

    void Login()
    {
        // Login...
    }

    void AddLog()
    {
        // ...
    }

    void SaveChanges()
    {
        //dbContext.SaveChanges()...
    }
}

Passing a dbcontext as parameter is in my point of view not a very good solution. But this is opinion based...

BendEg
  • 20,098
  • 17
  • 57
  • 131
  • This seems the more typical approach. I don't like the idea of passing around the datacontext and I haven't seen that done in any production code I've worked on. – jazza1000 Sep 09 '15 at 09:09
  • With my solution you do not pass around any datacontext, that is the idea. You have one instance of UserLogin (for example for one request). Because UserLogin contains the datacontext, you have only one... – BendEg Sep 09 '15 at 09:20
5

You can use the dbcontext as follows:

Action: Login

using(TempDBEntity context = new TempDBEntity())
{
   var temp = context.Users.Where(m => m.user_unique_id == 1).FirstOrDefault();
   temp.timestamp = new DateTime();
   temp.AddLog("Login", context);
}

Function: AddLog

public void AddLog(string activity, TempDBEntity context)
{
    var log = new UserLog();
    log.user_id = this.user_id;
    log.activity = activity;
    context.UserLog.Add(log);
    context.SaveChanges(); 
}

This will properly dispose the object after its use.

Tushar
  • 140
  • 7
  • 6
    good, but i would put the `SaveChanges()` at the main method level. – tschmit007 Sep 09 '15 at 08:44
  • I am skeptical of this, I'd prefer to see more upvotes to have confidence this it's true -- that passing an IDisposable in general (and a DbContext in particular) into a function would still properly dispose . But I believe it -- after all, why wouldn't it? -- that's the power of the using block. Even if an exception occurs, it's get disposed. But are there any other consequences, other than the "strangeness" of getting passed a DbContext you didn't create yourself? – Nate Anderson Oct 20 '16 at 03:47
  • Also wondering about @tschmit007's comment... I guess... if you're not responsible for creating DbContext, I'd guess you shouldn't be saving. Doesn't a single `SaveChanges()` work like a transaction i.e. a transaction around any Entity Framework changes since the most recent `SaveChanges()`? Not sure if I'd trust a method to decide when to "commit" a transaction -- but if I trusted it with my DbContext, I guess I'd trust it to decide when to SaveChanges()! – Nate Anderson Oct 20 '16 at 03:50
  • 1
    @TheRedPea usually I use a repository encapsulating/masking the dbcontext. The repo allows the business layer to perform/claim one or more operations (in one transaction) to the repo. When the business layer finishes the operations it claims a commit to the repo. – tschmit007 Oct 20 '16 at 14:42
1
I think you don't need to create new context in your AddLog function, you can pass the same first context to your AddLog function and then add your UserLogs to that without calling savechanges like this-

public void AddLog(TempDBEntity context, string activity){
        var log = new UserLog();
        log.user_id = this.user_id;
        log.activity = activity;
        context.UserLog.Add(log);
 }
Ankit Sahrawat
  • 1,306
  • 1
  • 11
  • 24