SlideShare a Scribd company logo
1 of 80
Download to read offline
PofEAA and
SQLAlchemy
INADA Naoki
@methane
Public Activity
MessagePack-Python
JSON like binary protocol
wsaccel
WebSocket accelerator for Tornado, ws4py
MyKaze
PyMySQL in Tornado (WIP)
Python for PHPer
Quick guide of Python for PHPer (Japanese)
Online Game Developer
R&D and Architect
Tuning server side middleware and application
KLab Inc.
SQLAlchemy
Great O/R Mapper
for Python
Patterns of
Enterprise Application
Architecture
Design patterns
good to know
for Web Programmers
SQLAlchemy
Quickly
(from tutorial)
● Dialects -- Various DB-API wrapper
● Engine -- Connection management
● Schema and Types
● SQL expression
● and O/R Mapper
SQLAlchemy features
Create Engine
from 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()
Define Object and Schema
from 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)
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)
)
Create an instance
>>> ed_user = User(name='ed',
... email='ed@example.com',
... password='edspassword')
...
>>> ed_user.password
'edspassword'
>>> str(ed_user.id)
'None'
Save it
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
session = Session()
session.add(ed_user)
session.commit()
Too complicated?
Why not just
engine.save(user)
What's session?
Session is Unit of Work
Unit of Work is
a Pattern
in PofEAA
Part 1. The Narratives
3. Mapping to RDB
Part 2. The Patterns
10. Data Source Architectural Patterns
11. O/R Behavioral Patterns
12. O/R Structural Patterns
13. O/R Metadata Mapping Patterns
O/R chapters in the P of EAA
Part 1. The Narratives
3. Mapping to RDB
Part 2. The Patterns
10. Data Source Architectural Patterns
11. O/R Behavioral Patterns
12. O/R Structural Patterns
13. O/R Metadata Mapping Patterns
O/R chapters in the P of EAA
11. O/R Behavioral Patterns
● Unit of Work
● Identity map
● Lazy load
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
Why Unit of Work
Remove boilerplate saving code from domain
logic.
Avoid objects saved too often.
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
Object states
user = User(...)
# Transient (not saved)
session.add(user)
# pending (saved)
session.flush()
# persistent (saved if modified)
session.expunge(user)
# Detached (not saved)
Flushing
Execute insert / update /delete query.
Session flushes automatically when querying
to avoid inconsistent result. (autoflush)
You can stop autoflush.
You can manually flush.
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.
Contextual Session
from sqlalchemy.orm import (sessionmaker,
scoped_session)
Session = scoped_session(
sessionmaker(bind=engine))
Session.add(ed_user)
Session.commit()
...
Session.remove()
11. O/R Behavioral Patterns
● Unit of Work
● Identity map
● Lazy load
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
Identity map in SQLAlchemy
Session has identity map.
# Looks up id map after querying
session.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.
11. O/R Behavioral Patterns
● Unit of Work
● Identity map
● Lazy load
Lazy Load
Load relation or heavy column on demand.
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.
Lazy loading big column
http://docs.sqlalchemy.
org/en/rel_0_8/orm/mapper_config.
html#deferred-column-loading
SQLAlchemy supports deferred column to
lazy loading big BLOB/TEXT.
O/R Structural Pattern
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
Object have PK in database as a field.
class Player(Base):
id = Column(INTEGER, primary=True)
Identity Field
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
Map one to one or one to many relation to
Object reference.
Not:
session.query(Address).get(user.address_id)
Yes:
user.address
Foreign Key Mapping
With property
from 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.
relationship
class User(Base):
...
addresses = relationship('Address',
backref='user')
class Address(Base):
...
user_id = Column(Integer,
ForeignKey('user.id'))
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
Association Table Mapping
Mapping many-to-many association table to
object 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
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
Dependent Mapping
O/R map ownership without identity.
PofEAA says:
I don’t recommend Dependent Mapping
if you’re using Unit of Work.
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
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,
…
);
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
Embedded Value by Composite
http://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
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
Serialized LOB
Serialize objects and save to XLOB column.
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)
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
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
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.
Single Table Inheritance in SQLA
class 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}
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
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.
Class table inheritance in SQLA
SQLA call it “Joined table inheritance”
http://docs.sqlalchemy.org/en/latest/orm/extensions/declarative.html#joined-
table-inheritance
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}
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
Mix-in
class 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
Concrete Table Inheritance in SQLA
http://docs.sqlalchemy.org/en/latest/orm/inheritance.
html#concrete-table-inheritance
10. Data Source Architectural Patterns
● Table Data Gateway
● Row Data Gateway
● Active Record
● Data Mapper
● Architectural Pattern and SQLAlchemy
Table Data Gateway
Target: Split querying from your domain logic
How: 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)
Row Data Gateway
Target: Split querying from your domain logic
How: 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)
Active Record
Row Data Gateway with Domain Logic
class Player:
@classmethod
def find_by_id(cls, id)
...
def birthday(self):
self.age += 1
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)
Architectural Patterns
and SQLAlchemy
My personal consideration
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)
Table Gateway?
Most tables doesn’t require Table Gateway.
When there are some complex queries,
Table Gateway is good to have.
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
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.
Fat Model (™)
Person.register(...) # class method
person.unregister()
person.request_friend(other_person_id)
...
Simple ActiveRecord & Service
class AccountService:
def register(self, name, email, age,...)
def unregister(self, person_id)
class FriendService:
def request(self,
from_person_id, to_person_id)
Finder in Service
When 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()
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
When you design large
application or framework,
PofEAA helps you lot.

More Related Content

What's hot

Web осень 2012 лекция 6
Web осень 2012 лекция 6Web осень 2012 лекция 6
Web осень 2012 лекция 6Technopark
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11Michelangelo van Dam
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksNate Abele
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful softwareJorn Oomen
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionLithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionNate Abele
 
The State of Lithium
The State of LithiumThe State of Lithium
The State of LithiumNate Abele
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 MinutesAzim Kurt
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & RESTHugo Hamon
 
Tools for Making Machine Learning more Reactive
Tools for Making Machine Learning more ReactiveTools for Making Machine Learning more Reactive
Tools for Making Machine Learning more ReactiveJeff Smith
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony TechniquesKris Wallsmith
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteLeonardo Proietti
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownpartsBastian Feder
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Leonardo Proietti
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixturesBill Chang
 
Dirty Secrets of the PHP SOAP Extension
Dirty Secrets of the PHP SOAP ExtensionDirty Secrets of the PHP SOAP Extension
Dirty Secrets of the PHP SOAP ExtensionAdam Trachtenberg
 
Windows Server 2008 (PowerShell Scripting Uygulamaları)
Windows Server 2008 (PowerShell Scripting Uygulamaları)Windows Server 2008 (PowerShell Scripting Uygulamaları)
Windows Server 2008 (PowerShell Scripting Uygulamaları)ÇözümPARK
 
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)Javier Eguiluz
 
international PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secretsinternational PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secretssmueller_sandsmedia
 

What's hot (20)

Web осень 2012 лекция 6
Web осень 2012 лекция 6Web осень 2012 лекция 6
Web осень 2012 лекция 6
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate Frameworks
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful software
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionLithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
 
The State of Lithium
The State of LithiumThe State of Lithium
The State of Lithium
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
Tools for Making Machine Learning more Reactive
Tools for Making Machine Learning more ReactiveTools for Making Machine Learning more Reactive
Tools for Making Machine Learning more Reactive
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony Techniques
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il cliente
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
 
Dirty Secrets of the PHP SOAP Extension
Dirty Secrets of the PHP SOAP ExtensionDirty Secrets of the PHP SOAP Extension
Dirty Secrets of the PHP SOAP Extension
 
Windows Server 2008 (PowerShell Scripting Uygulamaları)
Windows Server 2008 (PowerShell Scripting Uygulamaları)Windows Server 2008 (PowerShell Scripting Uygulamaları)
Windows Server 2008 (PowerShell Scripting Uygulamaları)
 
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
 
international PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secretsinternational PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secrets
 
ERRest in Depth
ERRest in DepthERRest in Depth
ERRest in Depth
 
New in php 7
New in php 7New in php 7
New in php 7
 

Similar to PofEAA and SQLAlchemy

Oracle Objects And Transactions
Oracle Objects And TransactionsOracle Objects And Transactions
Oracle Objects And Transactionstepsum
 
Go Faster With Native Compilation
Go Faster With Native CompilationGo Faster With Native Compilation
Go Faster With Native CompilationPGConf APAC
 
Go faster with_native_compilation Part-2
Go faster with_native_compilation Part-2Go faster with_native_compilation Part-2
Go faster with_native_compilation Part-2Rajeev Rastogi (KRR)
 
An Overview Of Python With Functional Programming
An Overview Of Python With Functional ProgrammingAn Overview Of Python With Functional Programming
An Overview Of Python With Functional ProgrammingAdam Getchell
 
Spring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard WolffSpring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard WolffJAX London
 
Node.js Patterns for Discerning Developers
Node.js Patterns for Discerning DevelopersNode.js Patterns for Discerning Developers
Node.js Patterns for Discerning Developerscacois
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing UpDavid Padbury
 
TI1220 Lecture 14: Domain-Specific Languages
TI1220 Lecture 14: Domain-Specific LanguagesTI1220 Lecture 14: Domain-Specific Languages
TI1220 Lecture 14: Domain-Specific LanguagesEelco Visser
 
Uncommon Design Patterns
Uncommon Design PatternsUncommon Design Patterns
Uncommon Design PatternsStefano Fago
 
Dragoncraft Architectural Overview
Dragoncraft Architectural OverviewDragoncraft Architectural Overview
Dragoncraft Architectural Overviewjessesanford
 
Implementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with SlickImplementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with SlickHermann Hueck
 
Ejb3 Struts Tutorial En
Ejb3 Struts Tutorial EnEjb3 Struts Tutorial En
Ejb3 Struts Tutorial EnAnkur Dongre
 
Ejb3 Struts Tutorial En
Ejb3 Struts Tutorial EnEjb3 Struts Tutorial En
Ejb3 Struts Tutorial EnAnkur Dongre
 
SE2016 BigData Vitalii Bondarenko "HD insight spark. Advanced in-memory Big D...
SE2016 BigData Vitalii Bondarenko "HD insight spark. Advanced in-memory Big D...SE2016 BigData Vitalii Bondarenko "HD insight spark. Advanced in-memory Big D...
SE2016 BigData Vitalii Bondarenko "HD insight spark. Advanced in-memory Big D...Inhacking
 
Vitalii Bondarenko HDinsight: spark. advanced in memory big-data analytics wi...
Vitalii Bondarenko HDinsight: spark. advanced in memory big-data analytics wi...Vitalii Bondarenko HDinsight: spark. advanced in memory big-data analytics wi...
Vitalii Bondarenko HDinsight: spark. advanced in memory big-data analytics wi...Аліна Шепшелей
 

Similar to PofEAA and SQLAlchemy (20)

Slickdemo
SlickdemoSlickdemo
Slickdemo
 
Oracle Objects And Transactions
Oracle Objects And TransactionsOracle Objects And Transactions
Oracle Objects And Transactions
 
Go Faster With Native Compilation
Go Faster With Native CompilationGo Faster With Native Compilation
Go Faster With Native Compilation
 
Go faster with_native_compilation Part-2
Go faster with_native_compilation Part-2Go faster with_native_compilation Part-2
Go faster with_native_compilation Part-2
 
An Overview Of Python With Functional Programming
An Overview Of Python With Functional ProgrammingAn Overview Of Python With Functional Programming
An Overview Of Python With Functional Programming
 
Spring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard WolffSpring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard Wolff
 
Scala and Spring
Scala and SpringScala and Spring
Scala and Spring
 
Go Faster With Native Compilation
Go Faster With Native CompilationGo Faster With Native Compilation
Go Faster With Native Compilation
 
Node.js Patterns for Discerning Developers
Node.js Patterns for Discerning DevelopersNode.js Patterns for Discerning Developers
Node.js Patterns for Discerning Developers
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing Up
 
TI1220 Lecture 14: Domain-Specific Languages
TI1220 Lecture 14: Domain-Specific LanguagesTI1220 Lecture 14: Domain-Specific Languages
TI1220 Lecture 14: Domain-Specific Languages
 
Sqlapi0.1
Sqlapi0.1Sqlapi0.1
Sqlapi0.1
 
Uncommon Design Patterns
Uncommon Design PatternsUncommon Design Patterns
Uncommon Design Patterns
 
Dragoncraft Architectural Overview
Dragoncraft Architectural OverviewDragoncraft Architectural Overview
Dragoncraft Architectural Overview
 
Lobos Introduction
Lobos IntroductionLobos Introduction
Lobos Introduction
 
Implementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with SlickImplementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with Slick
 
Ejb3 Struts Tutorial En
Ejb3 Struts Tutorial EnEjb3 Struts Tutorial En
Ejb3 Struts Tutorial En
 
Ejb3 Struts Tutorial En
Ejb3 Struts Tutorial EnEjb3 Struts Tutorial En
Ejb3 Struts Tutorial En
 
SE2016 BigData Vitalii Bondarenko "HD insight spark. Advanced in-memory Big D...
SE2016 BigData Vitalii Bondarenko "HD insight spark. Advanced in-memory Big D...SE2016 BigData Vitalii Bondarenko "HD insight spark. Advanced in-memory Big D...
SE2016 BigData Vitalii Bondarenko "HD insight spark. Advanced in-memory Big D...
 
Vitalii Bondarenko HDinsight: spark. advanced in memory big-data analytics wi...
Vitalii Bondarenko HDinsight: spark. advanced in memory big-data analytics wi...Vitalii Bondarenko HDinsight: spark. advanced in memory big-data analytics wi...
Vitalii Bondarenko HDinsight: spark. advanced in memory big-data analytics wi...
 

Recently uploaded

Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 

Recently uploaded (20)

Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 

PofEAA and SQLAlchemy

  • 2.
  • 3. Public Activity MessagePack-Python JSON like binary protocol wsaccel WebSocket accelerator for Tornado, ws4py MyKaze PyMySQL in Tornado (WIP) Python for PHPer Quick guide of Python for PHPer (Japanese)
  • 4. Online Game Developer R&D and Architect Tuning server side middleware and application KLab Inc.
  • 8. Design patterns good to know for Web Programmers
  • 10. ● Dialects -- Various DB-API wrapper ● Engine -- Connection management ● Schema and Types ● SQL expression ● and O/R Mapper SQLAlchemy features
  • 11. Create Engine from 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()
  • 12. Define Object and Schema from 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)
  • 13. 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) )
  • 14. Create an instance >>> ed_user = User(name='ed', ... email='ed@example.com', ... password='edspassword') ... >>> ed_user.password 'edspassword' >>> str(ed_user.id) 'None'
  • 15. Save it from sqlalchemy.orm import sessionmaker Session = sessionmaker(bind=engine) session = Session() session.add(ed_user) session.commit()
  • 18. Session is Unit of Work
  • 19. Unit of Work is a Pattern in PofEAA
  • 20. Part 1. The Narratives 3. Mapping to RDB Part 2. The Patterns 10. Data Source Architectural Patterns 11. O/R Behavioral Patterns 12. O/R Structural Patterns 13. O/R Metadata Mapping Patterns O/R chapters in the P of EAA
  • 21. Part 1. The Narratives 3. Mapping to RDB Part 2. The Patterns 10. Data Source Architectural Patterns 11. O/R Behavioral Patterns 12. O/R Structural Patterns 13. O/R Metadata Mapping Patterns O/R chapters in the P of EAA
  • 22. 11. O/R Behavioral Patterns ● Unit of Work ● Identity map ● Lazy load
  • 23. 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
  • 24. Why Unit of Work Remove boilerplate saving code from domain logic. Avoid objects saved too often.
  • 25. 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
  • 26. Object states user = User(...) # Transient (not saved) session.add(user) # pending (saved) session.flush() # persistent (saved if modified) session.expunge(user) # Detached (not saved)
  • 27. Flushing Execute insert / update /delete query. Session flushes automatically when querying to avoid inconsistent result. (autoflush) You can stop autoflush. You can manually flush.
  • 28. 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.
  • 29. Contextual Session from sqlalchemy.orm import (sessionmaker, scoped_session) Session = scoped_session( sessionmaker(bind=engine)) Session.add(ed_user) Session.commit() ... Session.remove()
  • 30. 11. O/R Behavioral Patterns ● Unit of Work ● Identity map ● Lazy load
  • 31. 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
  • 32. Identity map in SQLAlchemy Session has identity map. # Looks up id map after querying session.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.
  • 33. 11. O/R Behavioral Patterns ● Unit of Work ● Identity map ● Lazy load
  • 34. Lazy Load Load relation or heavy column on demand.
  • 35. 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.
  • 36. Lazy loading big column http://docs.sqlalchemy. org/en/rel_0_8/orm/mapper_config. html#deferred-column-loading SQLAlchemy supports deferred column to lazy loading big BLOB/TEXT.
  • 38. 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
  • 39. Object have PK in database as a field. class Player(Base): id = Column(INTEGER, primary=True) Identity Field
  • 40. 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
  • 41. Map one to one or one to many relation to Object reference. Not: session.query(Address).get(user.address_id) Yes: user.address Foreign Key Mapping
  • 42. With property from 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.
  • 43. relationship class User(Base): ... addresses = relationship('Address', backref='user') class Address(Base): ... user_id = Column(Integer, ForeignKey('user.id'))
  • 44. 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
  • 45. Association Table Mapping Mapping many-to-many association table to object 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
  • 46. 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
  • 47. Dependent Mapping O/R map ownership without identity. PofEAA says: I don’t recommend Dependent Mapping if you’re using Unit of Work.
  • 48. 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
  • 49. 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, … );
  • 50. 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
  • 51. Embedded Value by Composite http://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
  • 52. 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
  • 53. Serialized LOB Serialize objects and save to XLOB column.
  • 54. 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)
  • 55. 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
  • 56. 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
  • 57. 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.
  • 58. Single Table Inheritance in SQLA class 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}
  • 59. 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
  • 60. 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.
  • 61. Class table inheritance in SQLA SQLA call it “Joined table inheritance” http://docs.sqlalchemy.org/en/latest/orm/extensions/declarative.html#joined- table-inheritance
  • 62. 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}
  • 63. 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
  • 64. Mix-in class 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
  • 65. Concrete Table Inheritance in SQLA http://docs.sqlalchemy.org/en/latest/orm/inheritance. html#concrete-table-inheritance
  • 66. 10. Data Source Architectural Patterns ● Table Data Gateway ● Row Data Gateway ● Active Record ● Data Mapper ● Architectural Pattern and SQLAlchemy
  • 67. Table Data Gateway Target: Split querying from your domain logic How: 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)
  • 68. Row Data Gateway Target: Split querying from your domain logic How: 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)
  • 69. Active Record Row Data Gateway with Domain Logic class Player: @classmethod def find_by_id(cls, id) ... def birthday(self): self.age += 1
  • 70. 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)
  • 72. 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)
  • 73. Table Gateway? Most tables doesn’t require Table Gateway. When there are some complex queries, Table Gateway is good to have.
  • 74. 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
  • 75. 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.
  • 76. Fat Model (™) Person.register(...) # class method person.unregister() person.request_friend(other_person_id) ...
  • 77. Simple ActiveRecord & Service class AccountService: def register(self, name, email, age,...) def unregister(self, person_id) class FriendService: def request(self, from_person_id, to_person_id)
  • 78. Finder in Service When 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()
  • 79. 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
  • 80. When you design large application or framework, PofEAA helps you lot.