pofeaa and sqlalchemy
DESCRIPTION
TRANSCRIPT
![Page 1: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/1.jpg)
PofEAA andSQLAlchemy
INADA Naoki@methane
![Page 2: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/2.jpg)
![Page 3: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/3.jpg)
Public Activity
MessagePack-PythonJSON like binary protocol
wsaccelWebSocket accelerator for Tornado, ws4py
MyKazePyMySQL in Tornado (WIP)
Python for PHPerQuick guide of Python for PHPer (Japanese)
![Page 4: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/4.jpg)
Online Game Developer
R&D and ArchitectTuning server side middleware and application
KLab Inc.
![Page 5: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/5.jpg)
SQLAlchemy
![Page 6: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/6.jpg)
Great O/R Mapperfor Python
![Page 7: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/7.jpg)
Patterns ofEnterprise Application
Architecture
![Page 8: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/8.jpg)
Design patternsgood to know
for Web Programmers
![Page 9: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/9.jpg)
SQLAlchemyQuickly
(from tutorial)
![Page 10: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/10.jpg)
● Dialects -- Various DB-API wrapper
● Engine -- Connection management
● Schema and Types
● SQL expression
● and O/R Mapper
SQLAlchemy features
![Page 11: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/11.jpg)
Create Enginefrom sqlalchemy import create_engine
engine = create_engine('sqlite:///:memory:',
echo=True)
# Using engine without O/R mapper
con = engine.connect()
with con.begin() as trx:
con.execute('SELECT 1+1')
con.close()
![Page 12: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/12.jpg)
Define Object and Schemafrom sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
email = Column(String, nullable=False, unique=True)
password = Column(String, nullable=False)
![Page 13: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/13.jpg)
Create table on DB
Base.metadata.create_all(engine)
Output:CREATE TABLE users (
id INTEGER NOT NULL,
name VARCHAR,
email VARCHAR NOT NULL,
password VARCHAR NOT NULL,
PRIMARY KEY (id),
UNIQUE (email)
)
![Page 14: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/14.jpg)
Create an instance>>> ed_user = User(name='ed',
... email='[email protected]',
... password='edspassword')
...
>>> ed_user.password
'edspassword'
>>> str(ed_user.id)
'None'
![Page 15: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/15.jpg)
Save itfrom sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
session = Session()
session.add(ed_user)
session.commit()
![Page 16: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/16.jpg)
Too complicated?
![Page 17: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/17.jpg)
Why not just
engine.save(user)
What's session?
![Page 18: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/18.jpg)
Session is Unit of Work
![Page 19: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/19.jpg)
Unit of Work isa Pattern
in PofEAA
![Page 20: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/20.jpg)
Part 1. The Narratives3. Mapping to RDB
Part 2. The Patterns10. Data Source Architectural Patterns11. O/R Behavioral Patterns12. O/R Structural Patterns13. O/R Metadata Mapping Patterns
O/R chapters in the P of EAA
![Page 21: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/21.jpg)
Part 1. The Narratives3. Mapping to RDB
Part 2. The Patterns10. Data Source Architectural Patterns11. O/R Behavioral Patterns12. O/R Structural Patterns13. O/R Metadata Mapping Patterns
O/R chapters in the P of EAA
![Page 22: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/22.jpg)
11. O/R Behavioral Patterns
● Unit of Work
● Identity map
● Lazy load
![Page 23: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/23.jpg)
Unit of Work
Target: Maintains set of objects to save in transaction.
How:1. Wrap transaction.2. Keep track of new, modified and deleted objects.3. Save objects when commit
![Page 24: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/24.jpg)
Why Unit of Work
Remove boilerplate saving code from domain logic.
Avoid objects saved too often.
![Page 25: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/25.jpg)
Unit of Work in SQLAlchemy# Create an Unit of Work
session = Session()
# Get connection and start transaction
ed_user = session.query(User).\
filter(User.name=='ed').one()
ed_user.name='E.D.'
session.commit() # save ed_user and commit
![Page 26: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/26.jpg)
Object states
user = User(...)
# Transient (not saved)
session.add(user)
# pending (saved)
session.flush()
# persistent (saved if modified)
session.expunge(user)
# Detached (not saved)
![Page 27: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/27.jpg)
Flushing
Execute insert / update /delete query.
Session flushes automatically when queryingto avoid inconsistent result. (autoflush)
You can stop autoflush.You can manually flush.
![Page 28: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/28.jpg)
expire -- cause reload
session.expire(user)print(user.name) # Cause reloading
commit() # expires all objects for consistency.
You can avoid this by expire_on_commit=False.
![Page 29: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/29.jpg)
Contextual Sessionfrom sqlalchemy.orm import (sessionmaker,
scoped_session)
Session = scoped_session(
sessionmaker(bind=engine))
Session.add(ed_user)
Session.commit()
...
Session.remove()
![Page 30: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/30.jpg)
11. O/R Behavioral Patterns
● Unit of Work
● Identity map
● Lazy load
![Page 31: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/31.jpg)
Target:Avoid two objects for one record.
How:Keep mapping of (table, pk) -> object.Check the map when querying.
Bonus: It acts like a easy cache
Identity map
![Page 32: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/32.jpg)
Identity map in SQLAlchemy
Session has identity map.
# Looks up id map after queryingsession.query(User).filter(User.id==3).one()
# Looks up id map before and after querying.session.query(User).get(3)
NOTE: Id map is weak reference by default.
![Page 33: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/33.jpg)
11. O/R Behavioral Patterns
● Unit of Work
● Identity map
● Lazy load
![Page 34: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/34.jpg)
Lazy Load
Load relation or heavy column on demand.
![Page 35: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/35.jpg)
Lazy loading relationship
http://docs.sqlalchemy.org/en/rel_0_8/orm/loading.html
SQLAlchemy uses lazy loading by default for relationship.
You can choose eager loading strategy.
![Page 36: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/36.jpg)
Lazy loading big column
http://docs.sqlalchemy.org/en/rel_0_8/orm/mapper_config.html#deferred-column-loading
SQLAlchemy supports deferred column tolazy loading big BLOB/TEXT.
![Page 37: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/37.jpg)
O/R Structural Pattern
![Page 38: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/38.jpg)
12. O/R Structural Pattern
● Identity Field● Foreign Key Mapping● Association Table Mapping● Dependent Mapping● Embedded Value● Serialized LOB● Single Table Inheritance● Class Table Inheritance● Concrete Table Inheritance● Inheritance Mappers
![Page 39: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/39.jpg)
Object have PK in database as a field.
class Player(Base):
id = Column(INTEGER, primary=True)
Identity Field
![Page 40: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/40.jpg)
12. O/R Structural Pattern
● Identity Field● Foreign Key Mapping● Association Table Mapping● Dependent Mapping● Embedded Value● Serialized LOB● Single Table Inheritance● Class Table Inheritance● Concrete Table Inheritance● Inheritance Mappers
![Page 41: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/41.jpg)
Map one to one or one to many relation toObject reference.
Not:session.query(Address).get(user.address_id)
Yes:user.address
Foreign Key Mapping
![Page 42: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/42.jpg)
With propertyfrom werkzeug.utils.cached_property
class User(Base):
...
@cached_property
def address(self):
session.query(Address).\
get(self.address_id)
This is enough to achieve ``user.address``.
But no SQLA support.
![Page 43: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/43.jpg)
relationshipclass User(Base):
...
addresses = relationship('Address',
backref='user')
class Address(Base):
...
user_id = Column(Integer,
ForeignKey('user.id'))
![Page 44: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/44.jpg)
12. O/R Structural Pattern
● Identity Field● Foreign Key Mapping● Association Table Mapping● Dependent Mapping● Embedded Value● Serialized LOB● Single Table Inheritance● Class Table Inheritance● Concrete Table Inheritance● Inheritance Mappers
![Page 45: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/45.jpg)
Association Table Mapping
Mapping many-to-many association table toobject reference.
In SQLAlchemy:Pass “secondary” argument to relationship()http://docs.sqlalchemy.org/en/rel_0_8/orm/tutorial.html#building-a-many-to-many-relationship
![Page 46: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/46.jpg)
12. O/R Structural Pattern
● Identity Field● Foreign Key Mapping● Association Table Mapping● Dependent Mapping● Embedded Value● Serialized LOB● Single Table Inheritance● Class Table Inheritance● Concrete Table Inheritance● Inheritance Mappers
![Page 47: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/47.jpg)
Dependent Mapping
O/R map ownership without identity.
PofEAA says:
I don’t recommend Dependent Mapping if you’re using Unit of Work.
![Page 48: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/48.jpg)
12. O/R Structural Pattern
● Identity Field● Foreign Key Mapping● Association Table Mapping● Dependent Mapping● Embedded Value● Serialized LOB● Single Table Inheritance● Class Table Inheritance● Concrete Table Inheritance● Inheritance Mappers
![Page 49: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/49.jpg)
Embedded Value
Map an object to some columns in a row.
class Duration: start_date end_date
class Account: duration
CREATE TABLE account ( … start_date DATE, end_date DATE, …);
![Page 50: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/50.jpg)
Embedded Value by property@property
def duration(self):
return Duration(
self.start_date, self.end_date)
@duration.setter
def duration(self, duration):
self.start_date = duration.start
self.end_date = duration.end
![Page 51: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/51.jpg)
Embedded Value by Compositehttp://docs.sqlalchemy.org/en/rel_0_8/orm/mapper_config.html#mapper-composite
class Account(Base):
...
start_date = Column(DATE)
end_date = Column(DATE)
duration = composite(Duration, start_date, end_date)
class Duration(namedtuple(‘Duration’, ‘start end’)):
def __composite_value__(self):
return self
![Page 52: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/52.jpg)
12. O/R Structural Pattern
● Identity Field● Foreign Key Mapping● Association Table Mapping● Dependent Mapping● Embedded Value● Serialized LOB● Single Table Inheritance● Class Table Inheritance● Concrete Table Inheritance● Inheritance Mappers
![Page 53: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/53.jpg)
Serialized LOB
Serialize objects and save to XLOB column.
![Page 54: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/54.jpg)
Using property
_info = Column('info', BLOB)
@property
def info(self):
return json.loads(self._info)
@info.setter
def _set_info(self, info):
self._info = json.dumps(self)
![Page 55: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/55.jpg)
Custom Type
SQLAlchemy provides PickleType for serialized LOB.
You can define custom type via TypeDecorator:http://docs.sqlalchemy.org/en/rel_0_8/core/types.html#marshal-json-strings
![Page 56: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/56.jpg)
12. O/R Structural Pattern
● Identity Field● Foreign Key Mapping● Association Table Mapping● Dependent Mapping● Embedded Value● Serialized LOB● Single Table Inheritance● Class Table Inheritance● Concrete Table Inheritance● Inheritance Mappers
![Page 57: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/57.jpg)
Single Table Inheritance
Player
SoccerPlayer BaseballPlayer
CREATE TABLE player( id INTEGER PRIMARY KEY, type INTEGER NOT NULL, position INTEGER,)
All classes saved into one table.
![Page 58: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/58.jpg)
Single Table Inheritance in SQLAclass Player(Base):
__tablename__ = ‘player’
id = Column(INTEGER, primary_key=True)
position = Column(INTEGER)
type = Column(INTEGER, nullable=False)
__mapper_args__ = {‘polymorphic_on’: type}
SOCCER_PLAYER = 1
BASEBALL_PLAYER = 2
class SoccerPlayer(Player):
__mapper_args__ = {
‘polymorhic_identity’: Player.SOCCER_PLAYER}
![Page 59: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/59.jpg)
Defining columns in subclass
Defining columns in subclass may cause conflict.
SQLA provides way to avoid it. See below.http://docs.sqlalchemy.org/en/latest/orm/extensions/declarative.html#resolving-column-conflicts
![Page 60: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/60.jpg)
Class Table Inheritance
Player
SoccerPlayer BaseballPlayer
CREATE TABLE player( id INTEGER PRIMARY KEY, type INTEGER NOT NULL)CREATE TABLE soccer_player( id INTEGER PRIMARY KEY, position INTEGER NOT NULL)CREATE TABLE baseball_player( id INTEGER PRIMARY KEY, position INTEGER NOT NULL)
Tables for each classes.
![Page 61: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/61.jpg)
Class table inheritance in SQLA
SQLA call it “Joined table inheritance”http://docs.sqlalchemy.org/en/latest/orm/extensions/declarative.html#joined-table-inheritance
![Page 62: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/62.jpg)
class Player(Base):
__tablename__ = 'player'
id = Column(INTEGER, primary_key=True)
type = Column(INTEGER, nullable=False)
SOCCER_PLAYER = 1
BASEBALL_PLAYER = 2
__mapper_args__ = {'polymorphic_on': type}
class SoccerPlayer(Player):
__tablename__ = 'soccer_player'
id = Column(ForeignKey('player.id'), primary_key=True)
position = Column(INTEGER, nullable=False)
__mapper_args__ = {
'polymorhic_identity': Player.SOCCER_PLAYER}
![Page 63: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/63.jpg)
Concrete Table Inheritance
Player
SoccerPlayer BaseballPlayer
CREATE TABLE soccer_player( id INTEGER PRIMARY KEY, name VARCHAR(32) NOT NULL, position INTEGER NOT NULL)
CREATE TABLE baseball_player( id INTEGER PRIMARY KEY, name VARCHAR(32) NOT NULL, position INTEGER NOT NULL)
Tables for each concrete classes
![Page 64: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/64.jpg)
Mix-inclass BasePlayer(object):
id = Column(INTEGER, primary_key=True)
name = Column(VARCHAR(32), nullable=False)
class SoccerPlayer(BasePlayer, Base):
__tablename__ = ‘soccer_player’
position = Column(INTEGER, nullable=False)
Pros) Simple.Cons) You can’t get support from SQLAlchemy
![Page 65: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/65.jpg)
Concrete Table Inheritance in SQLA
http://docs.sqlalchemy.org/en/latest/orm/inheritance.html#concrete-table-inheritance
![Page 66: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/66.jpg)
10. Data Source Architectural Patterns
● Table Data Gateway
● Row Data Gateway
● Active Record
● Data Mapper
● Architectural Pattern and SQLAlchemy
![Page 67: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/67.jpg)
Table Data Gateway
Target: Split querying from your domain logicHow: Create gateway for each table.
class PlayerGateway:
def find_by_id(self, id)
def find_by_name(self, name)
def update(self, id, name=None, age=None)
def insert(self, id, name, age)
![Page 68: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/68.jpg)
Row Data Gateway
Target: Split querying from your domain logicHow: Create gateway for each record.
class PlayerGateway:
@classmethod
def find_by_id(cls, id):
… return cls(id, name, age)
… def insert(self)
def update(self)
![Page 69: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/69.jpg)
Active Record
Row Data Gateway with Domain Logic
class Player:
@classmethod
def find_by_id(cls, id)
...
def birthday(self):
self.age += 1
![Page 70: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/70.jpg)
Data Mapper
Target: Split out column/attribute mapping code from your domain logic.
class PersonMapper(BaseMapper):
def map(self, row):
return Person(id=row.id,
name=row.name,
age=row.age)
![Page 71: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/71.jpg)
Architectural Patternsand SQLAlchemy
My personal consideration
![Page 72: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/72.jpg)
Querying in SQLAlchemy
Unit of Work handles most of update and insert queries.
Easy query can be written very easy.(Building complex query is hard)
![Page 73: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/73.jpg)
Table Gateway?
Most tables doesn’t require Table Gateway.
When there are some complex queries,Table Gateway is good to have.
![Page 74: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/74.jpg)
Row Data Gateway?Active Record?
Separating model object and row data gateway cause additional complexity.For example, does your model need identity map?
Person
Person
PersonRow
![Page 75: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/75.jpg)
Active Record drawbacks
Problem: Good table design is not good class design always.My answer: Use structural patterns like Embedded Value.
P: Mixing database access and domain logic is bad idea.A: Use Table Gateway to separate them.
![Page 76: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/76.jpg)
Fat Model (™)
Person.register(...) # class methodperson.unregister()person.request_friend(other_person_id)...
![Page 77: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/77.jpg)
Simple ActiveRecord & Serviceclass AccountService:
def register(self, name, email, age,...)
def unregister(self, person_id)
class FriendService:
def request(self,
from_person_id, to_person_id)
![Page 78: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/78.jpg)
Finder in ServiceWhen you use service classes, you may be able to put finders there and don’t use Table Gateway.
class PersonService:
...
def find_by_name(self, name):
return Session.query(Person). \
filter_by(name=name).all()
![Page 79: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/79.jpg)
Anemic Domain Model
http://www.martinfowler.com/bliki/AnemicDomainModel.html
P: Implementing all domain logic in service is not a OOP.
A: Simple Active Record + Medium sized classes + Service
![Page 80: PofEAA and SQLAlchemy](https://reader033.vdocuments.net/reader033/viewer/2022051314/54c6b8784a79597d178b4671/html5/thumbnails/80.jpg)
When you design large application or framework,
PofEAA helps you lot.