2

Let's say I have a method that loads some entities from database, makes an API call for each, gets a token from a third party and saves them. The API call is critical so we want each call to be logged into db instantly.
So I put context.SaveChanges in CriticalAPI, to save each log separately.
The problem is that this SaveChanges also saves Posts entities modified in Method().
I want CriticalAPI to only save logs, not other objects. One way is to create another context and use in that method, but it violates dependency injection because I should instantiate a new context in my method.
What is the correct way to achieve this requirements?

public void Method(){
    var entities = context.Posts.Where(/* something */).ToList();
    foreach (var entity in entities){
         var result = CriticalAPI(entity.Id);
         entity.Token = result;
    }
    context.SaveChanges();
}

public int CriticalAPI(int id){
    var token = /* do something critical */
    context.Logs.Add(new Log(){
         entityId = id
    });
    context.SaveChanges();
    return token;
}

2 Answers 2

3

You can use abstract factory pattern. Just define context factory interface and inject the factory. Then use the factory anywhere you need to create new context instance:

interface IDbContextFactory {
    DbContext CreateContext();
}

//...

public void Method() {
    using (var context = contextFactory.CreateContext()) {
        context.Posts.Where(/* something */)
            .ForEach(entity => {
                var result = CriticalAPI(entity.Id);
                entity.Token = result;
            });
        context.SaveChanges();
    }
}

public int CriticalAPI(int id) {
    using (var context = contextFactory.CreateContext()) {
        var token = /* do something critical */
        context.Logs.Add(new Log(){
            entityId = id
        });
        context.SaveChanges();
        return token;
    }
}

Sign up to request clarification or add additional context in comments.

1 Comment

Great way to do so
0

You can add .AsNoTracking() method after when you're calling context.Posts and the entity will not track changes.

public void method(){
    var entities = context.Posts
             .AsNoTracking() //  <---- add this Method here
             .Where(/* something */).ToList();
    foreach (var entity in entities){
         var result = CriticalAPI(entity.Id);
         entity.Token = result;
    }
    context.SaveChanges();
}

You could alternatively create an ENTIRELY separate dbContext for Logs, and you would set and save that context.

2 Comments

I want Posts to be saved, but not in the middle of the loop and by CriticalAPI(). I want alll Posts to be saved at the end of method()
Then I think you would want to create an entirely seperate dbContext for logs, where the only DbSet is Logs. You'd remove that whatever context Post is in, and then you can save your Logs independently of Posts.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.