Many thanks - it is much clearer now! Best regards
On Tuesday, September 21, 2021 at 5:25:41 PM UTC+2 Mike Bayer wrote: > > > On Tue, Sep 21, 2021, at 10:41 AM, Nikola Radovanovic wrote: > > Thank you. > > Maybe I did not explain well (English is not my first language): when I > declare a dataclass to serve as business model (so something passed around > the code, between libraries, layers, frameworks, etc.) - I don't want any > ORM stuff in it. No matter if it is hidden in private/protected attribute. > I just want ORM to be able to fill my dataclass after I fetch something > from the DB without leaving a "trace" in resulting object and to > "understand" dataclass when I perform insert/update (think of it as C > structure). Its not a problem if I have to write this "adapter" for the > needs of my project, just want to know if someone already did it and if > not, what would be the recommended way. > > > yeah i just dont see how there is any practical concern to that. i know > it "feels" ugly, but thats what ORMs do (all of them). the ORM is > explcitly a tool to instrument business objects with persistence logic. > > > > Book I am referring explains exact problems we had when initial project > layout was set: we dragged ORM in our business model and made business > model aware of the ORM instead the opposite. Seems there are quite other > people/teams made the very same mistake (otherwise there will be no book > about it). It is not related only to SqlAlchemy but rather how people > (mis)use ORMs in general and made their code hard to maintain (as we did > because we don't know better atm). > > > yes this is a common thing among architectural communities. The simple > answer is that these model objects would have to have nothing to do with > the SQLAlchemy ORM period if you want your business model to have > absolutely zero linkage to the persistence details. The _sa_class_state > and _sa_instance_state is the least of your problems, SQLAlchemy ORM > applies instrumented descriptors to your classes as well. that's the whole > way that things like MyModel.column has SQL behavior, how "my_model.column" > has data in it, how "my_model.list_of_related" has related objects, etc. > your business methods on those classes then build off of those attributes, > which means those objects are fully dependent on the ORM. > > the standard way to architect for this pattern is to treat SQLAlchemy ORM > objects as specific to persistence, then have an entirely different copy of > the whole model as actual business objects. Then you have a data > persistence layer that runs queries in terms of ORM objects and can > translate them to your data objects. This is the pattern I would > recommend; by trying to use special instrumentation tricks, you're trying > to temporarily apply ORM instrumentation to objects that you otherwise > would prefer have nothing to do with the persistence, and that's just > wrong; these objects will have *everything* to do with persistence while > this process goes on. > > the above pattern is the one that is used by most of the Openstack > projects, for example, though they have steadily moved away from it due to > it being cumbersome. The pydantic project offers a standard recipe for > this kind of thing which you can see at > https://pydantic-docs.helpmanual.io/usage/models/#orm-mode-aka-arbitrary-class-instances > > , where you have your dataclasses on one side and your persistence /ORM > objects on the other. people are usually pretty annoyed by this pattern > so the SQLModel project https://github.com/tiangolo/sqlmodel aims to > simplify this by re-joining the two types of objects together, but in this > case if you are going for "purity" I dont think you can get around that you > will need to have two parallel object models and a data access layer in > between. > > > > I think SA is great ORM, I use it, recommend it to others and will > continue to do so - please don't take this as any sort of critique or > nitpicking, I am just looking some clues how to resolve problems we > encounter. > > > not at all! I know exactly what you're going for, and that's great. you > will need to have two separate layers though, trying to sneak by with > temporary instrumentation is not the way to do that. > > > Kindest regards > > On Tuesday, September 21, 2021 at 3:51:36 PM UTC+2 Mike Bayer wrote: > > > > On Mon, Sep 20, 2021, at 11:40 PM, Nikola Radovanovic wrote: > > Thank you, > I am reading Architecture Patterns with Python > <https://www.cosmicpython.com/book/chapter_02_repository.html> and trying > to find a way to refactor our code to become maintainable. However I > noticed that even with mapped dataclass there are problems like the one > mentioned here <https://github.com/cosmicpython/code/issues/17> and > proposed solution is to use *InstrumentationManager* you just mentioned, > but even with this approach resulting dataclass will be "linked" to ORM > object via internal attributes, defeating the purpose of Registry pattern > proposed in the book. > > > the instrumentation manager lets you change how this "link" occurs and > there doesnt need to be any attributes on the class. > > that said, I am not familiar with that book and if there is some aspect to > dataclasses that causes them to fail if there is some instrumentation on > them, that's a pretty serious shortcoming in dataclasses. > > > Would it be OK to simply use dict objects as adapter between dataclass and > ORM? > > > I proposed using a weakkeydictionary, so if that's what you mean, then > yes. again i am not famliiar with that book and im not really sure how > code is not "maintainable" if it has some private attributes on it. seems > pretty off. > > > > > > > Kindest regards > > On Monday, September 20, 2021 at 4:04:05 PM UTC+2 Mike Bayer wrote: > > > > On Mon, Sep 20, 2021, at 5:04 AM, Nikola Radovanovic wrote: > > > Hi, > When decoupling business from ORM model, dataclass passed to SA's > imperative mapper *map_imperatively* will receive SA's internals like for > example *_sa_instance_state* and *_sa_class_manager*. > > I am wondering, what would be the best way to have "pure" dataclass, > without SA internals? First thing to come to my mind is to perform query on > SA *Table* and use dict/namedtuple to populate dataclass. Are there > better approaches? I am in particular interested how this approach will > behave with partial and composite updates? Any recipe to recommend? > > > to accomplish that you use a registry, typically a weak-keyed one, where > keys are the classes / instances in use and the values are the class > managers and states. If you wanted to apply such a system to your classes > you would make use of the instrumentation extension system: > > https://docs.sqlalchemy.org/en/14/orm/extensions/instrumentation.html > > there's also an example of it : > > > https://docs.sqlalchemy.org/en/14/_modules/examples/custom_attributes/custom_management.html > > > > now as far as if you *should* do this. Absolutely not. The > instrumentation extension system is a very old and almost never used corner > of the API which I moved out of the main library some years ago due to its > complexity. adding a weakref lookup to all class/state instrumentation > lookups will add a palpable performance penalty to most ORM operations, and > the instrumentation extension is likely not without bugs and regressions at > this point. it was first created over ten years ago to suit the use case > of a single user who was working with Zope security proxied objects. > I've seen at least one other person using it, but overall i dont think it's > worthwhile to spend lots of time going down tunnels like this; if your > dataclass has a few attributes stuck on it, that shouldn't be a problem for > any real-world situation. > > > > > > > > Thank you in advance. > > Kindest regards > > > -- > SQLAlchemy - > The Python SQL Toolkit and Object Relational Mapper > > http://www.sqlalchemy.org/ > > To post example code, please provide an MCVE: Minimal, Complete, and > Verifiable Example. See http://stackoverflow.com/help/mcve for a full > description. > --- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sqlalchemy+...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/sqlalchemy/324223bc-695d-4479-be32-b1a7c73e8a76n%40googlegroups.com > > <https://groups.google.com/d/msgid/sqlalchemy/324223bc-695d-4479-be32-b1a7c73e8a76n%40googlegroups.com?utm_medium=email&utm_source=footer> > . > > > > -- > SQLAlchemy - > The Python SQL Toolkit and Object Relational Mapper > > http://www.sqlalchemy.org/ > > To post example code, please provide an MCVE: Minimal, Complete, and > Verifiable Example. See http://stackoverflow.com/help/mcve for a full > description. > --- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sqlalchemy+...@googlegroups.com. > > To view this discussion on the web visit > https://groups.google.com/d/msgid/sqlalchemy/3d3b6d37-d833-41a8-b414-2f41e7c601c3n%40googlegroups.com > > <https://groups.google.com/d/msgid/sqlalchemy/3d3b6d37-d833-41a8-b414-2f41e7c601c3n%40googlegroups.com?utm_medium=email&utm_source=footer> > . > > > > -- > SQLAlchemy - > The Python SQL Toolkit and Object Relational Mapper > > http://www.sqlalchemy.org/ > > To post example code, please provide an MCVE: Minimal, Complete, and > Verifiable Example. See http://stackoverflow.com/help/mcve for a full > description. > --- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sqlalchemy+...@googlegroups.com. > > To view this discussion on the web visit > https://groups.google.com/d/msgid/sqlalchemy/69ec0ab7-dfe1-492e-b3fd-c99c29e17b7dn%40googlegroups.com > > <https://groups.google.com/d/msgid/sqlalchemy/69ec0ab7-dfe1-492e-b3fd-c99c29e17b7dn%40googlegroups.com?utm_medium=email&utm_source=footer> > . > > > -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/ca0d1359-fc7c-4860-a983-348f02902d2dn%40googlegroups.com.