> On 13 Nov 2015, at 09:16, Yegor Roganov <[email protected]> wrote:
> 
> Suppose we have a 1 <-> N relation between users and cities (meaning that 
> every user is related with one city). For our domain model "User" we want to 
> define a method "lives_in_london". Code looks like this:
> 
> class User(Base):
>     id = ...
>     city_id = ...
>     city = relationship("City")
>     def lives_in_london(self):
>         return self.city.name == 'London'
> 
> class City(Base):
>     id = ...
>     name = Column(String)
> 
> The problem with this code is that "lives_in_london" method is a leaky 
> abstraction, its client must keep in mind that it may issue a DB query. It's 
> okay as a one-off thing, but will case problems if used in a loop.
> So to be used efficiently, clients must know to preload the "city" 
> relationship.
> 
> I know it's a contrived example, but the general question is how to define 
> domain methods that need to access relations. I also know that the question 
> is intrinsic to all ORM, but maybe SQLAlchemy could offer some support.

I have not yet found a really satisfying solution to this class of problems, 
but all the solutions are along the lines of "do not present such abstractions".

When there is a need to encapsulate some special knowledge about the data model 
(in your example, this is "self.city.name == 'London'"), I have seen three 
approaches:

Use higher level abstractions that perform all the required queries to produce 
"view" objects needed to complete a task. Those abstractions will tend to be 
tailored to a specific single use in the code base, but they will provide a 
convenient injection point to mock out the database layer for unit testing, and 
they can be easily identified and audited when the data model changes.
Detach mapped entity after loading to force client code to perform all the 
relationship loading explicitly. Kind of hackish, but that might work well in 
some cases.
Do not use mapped entities at all for read-only tasks, and instead load 
specific columns and use class methods on the models to encapsulate knowledge. 
That makes for simple code since there is no need to introduce an explicit view 
abstraction layer, but that might lead to code that is harder to test because 
the query generation code will be coupled with the code that uses the result of 
the query.

The common theme here is: do not let mapped objects attached to the session 
escape to code that should not know about which operations could generate 
relationship loading queries.

There is clear contrast between code that only reads the database, typically 
works on collections of objects, and should prevent mapped objects from leaking 
out. And code that writes to the database, typically works on individual 
objects, and lets client code update mapped objects.

-- 
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 [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to