Open JankesJanco opened 6 years ago
Possible related issue
Definition: I will use term transactional method for method which is decorated by @transactional decorator
class MyGreatService(Service):
@transactional
def get_foo(self, foo_id, db_session):
# ...
db_session.query(Foo).get(foo_id)
# ...
# usage
# db_session argument is set by @transactional decorator
my_great_service.get_foo(3)
# or when we already are inside transactional method, we can use existing db session
my_great_service.get_foo(3, db_session=existing_db_session)
Question: Can we get rid of Service class (base class of MyGreatService class) in case of this design?
Pros:
Cons:
There are 2 crucial objects in this design:
Note: For implementation we can use Local, LocalStack and LocalProxy classes from werkzeug.
Pros:
Cons:
After discussion in telegram the winning proposal is the first one Session as parameter in transactional method. The main reason is that first proposal meets all 4 design goals and is somehow cleaner solution while cons of second proposal (Sessions stored in sessionHolder object, current session accessible through sessionProxy) are significant.
Call inside @transactional method to another @transactional method from other Service class instance lead in some cases to error.
Following code will result in exception (
sqlalchemy.orm.exc.DetachedInstanceError
) raised at linefoo.bar_parent_name = bar.parent.name
when calling methodFooService.create_foo()
If you want, I can provide real-life use-case similar to this example. This behavior limit options to better split code into logic and reusable units.
Maybe we should open discussion about @transactional decorator design and implementation. Briefly said, nowadays @transactional decorator set db session to
_orm
property of Service class instance. I am not sure if it is ideal design. Maybe we could get inspiration from Java Spring framework where 2 types of classes are used - Services and Daos - and db session is not directly bound to class instances as in our case.