Comments (5)
I've just recently come across this library and still trying to understand the whole thing. But given that, here's my two cents on some of your concerns based on my current understanding.
- The Fund Transfer scenario (ie. TransferMoney and WithdrawMoney; btw, I think you meant DepositMoney and WithdrawMoney since those are what's involved in a fund transfer). In this case, based on the sample code of mehdime, the closest steps will probably be to do the ff:
- Create the DepositMoney method (with its own SaveChanges call since I think this is a distinct operation on its own);
- Create the WithdrawMoney method (with its own SaveChanges call since I think this is a distinct operation on its own too);
- Create a FundTransfer method that calls the DepositMoney and WithdrawMoney methods inside. The FundTransfer method will create its own scope which becomes the parent scope of the two (2) "child" methods. This way the commit and the rollback will be consistent.
That's the way I understand it. I haven't tested it yet but theoretically it should work.
My main concern however is different. It's related to this example code:
var user = dbContextScope.DbContexts.Get.Set.Find(userId);
(note: angle brackets are being removed in the sample code above; MyDbContext and User are missing);
It is the fact that in a Service method I can access a different DbContext and therefore directly call the Find, for example, on the entity on that different context, even if my design involves a repository. Ideally, if I wrapped my data access calls in a Repository, all of my data access calls should be encapsulated in that repository class and my service class simply calls the methods in the Repository. I think the way it is implemented right now is a bit leaky.
I wonder what will happen if the DbContexts collection is hidden from the caller.
Thanks.
from dbcontextscope.
I find readonly scopes to be particularly "magic" in their usage.
public UserDto GetUser(Guid userId)
{
using (var dbContextScope = _dbContextScopeFactory.CreateReadOnly())
{
var user = _userRepository.Get(userId);
var userDto = _mapper.Map<UserDto>(user);
return userDto;
}
}
Why was I required to create a scope? It's not used explicitly anywhere. This leads to fragile code where refactorings can cause run time errors.
from dbcontextscope.
For anyone coming across this question now, an answer the question by carbonrobot.
To transfer money, you would not have:
_service.TransferMoney(2000, account);
_service.WithdrawMoney(1200);
because as he points out, each of those two services would each call SaveChanges(), creating a request that is not atomic and can't be rolled back. Instead the way to handle this would be the following:
using (var dbContextScope = _dbContextScopeFactory.Create())
{
TransferMoney(2000, account);
WithdrawMoney(1200);
dbContextScope.SaveChanges();
}
void TransferMoney(int amount, Account account)
{
using (var dbContextScope = _dbContextScopeFactory.Create())
{
//transfer money...
dbContextScope.SaveChanges();
}
}
void WithdrawMoney(int amount)
{
using (var dbContextScope = _dbContextScopeFactory.Create())
{
//withdraw money...
dbContextScope.SaveChanges();
}
}
TransferMoney and Withdraw money still include their own SaveChanges() calls (because they can still be called on their own), but the SaveChanges method is ignored because DbContextScope detects an ambient DbContext that has already been created! This means you can avoid situations of messy and confusing DbContext scopes.
In comparison to the answer by nolisj. In that example you would have seperate method called FundTransfer with its own SaveChanges() call, but they wouldn't be able to implement TransferMoney or WithdrawMoney because they already implement their own DbContexts and call SaveChanges(). That's where without DbContextScope it starts to get messy.
(Edit: I misread the post by nolisj, his method is correct)
Likewise, in carbonrobots final example:
var transactions = new List<Transaction>(){
new TransferMoneyTransaction(2000, account),
new WithdrawMoneyTransaction(1200)
};
_service.Commit(transactions);
Would only work if TransferMoneyTransaction and WithdrawMoneyTransaction are designed not to be used on their own and do not call Commit/SaveChanges themselves, which could lead to a messy codebase when developers still need to use those actions on their own.
You can also see the power of this in the CreateListOfUsers method in the sample project where a service can either call CreateUser() on its own and the user will be persisted back to the database, or they can create a new ambient DbContextScope and then call CreateUser several times in a loop - it's the exact same method being called, but now because the ambient scope exists CreateUser() wont actually save the changes back to the DB - it's only once the loop is completed that the service then calls SaveChanges() to persist the updates in a single request for all the new users.
Hope that helps!
from dbcontextscope.
Boolean0101,
Thanks for your input. If you read closely, your answer is the same as mine. Your two independent "child" functions (TransferMoney and WithdrawMoney) become contained in a "parent" (aka container) function. It's just that you did not name your parent function. In my case, the DepositMoney and WithdrawMoney are the child functions which are called in the FundTransfer function. Each child function is independent (since you can deposit or withdraw separately) and can commit their own individual operations if called individually but can also participate in the fund transfer scenario if you so desire (which means there's a DbContextScope in the FundTransfer parent function also) . I hope that clarifies what I meant.
from dbcontextscope.
Hi nolisj
Right you are - I misread your last bullet point as not calling SaveChanges on itself and thought you were relying on the child methods to persist changes, which I realize wasn't what you meant. I think my post still adds some details to the answer though, so I'll update it to make it more clear.
from dbcontextscope.
Related Issues (20)
- Compatibility with Effort
- Use with EntityFramework Reverse POCO Code First Generator? HOT 1
- nested IDbContextFactory.CreateWithTransaction HOT 1
- Need way to disable disposing of DbContext when root DbContextScope is disposed HOT 3
- .net core HOT 2
- Unable to use a non-interfaced DbContext with DbContextScope HOT 2
- TDD with DbContextScope HOT 1
- Connect to database with a different user/connection string HOT 5
- Moving to .Net Standard 2.0 & EF 2.0 HOT 8
- Best practice for taking advantage of EF first-level caching in Domain Service Layer. HOT 5
- Working with Store Procedure and Transaction
- DbContextScope with EF Core !! HOT 6
- Dead link
- Problems when attaching new dbcontexts while performing savechanges
- The current type, EntityFramework.DbContextScope.Interfaces.IDbContextFactory, is an interface and cannot be constructed. Are you missing a type mapping?
- Suggestions: how to retrieve ID generated by DB after saveChanges() HOT 2
- how to use DbContextScope with Parallel.ForEach
- Satellite class to use the same Factory/Locator across application modules
- What to pass to IDbContextFactory argument in DbContextScope constructor? HOT 1
- Support of ASP.NET Core dependency injection out of the box
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from dbcontextscope.