未分類

ORMを使う意義

目的

  • ORMを使うのに否定的な意見があったので、どういう点がメリットかを記載する。

ORMとは

  • ORMとはObject Relational Mapperの略で、関係データベース(特にSQL)をオブジェクト指向プログラミングのオブジェクトとして扱う技術。
    • 簡単に言うとSQLをプログラミング言語で使用するための技術

メリット

  1. QLとプログラミングの親和性を高めることができる。一々、SQLからオブジェクトの変換をする必要がない。
  2. 関係データベースの抽象化が可能。
    • 例えば、SQLAlchemyのColumnにautoincrementがあるが、PostgreSQLはSerial、MySQLはauto incrementとして解釈される。これはSQLAlchemyのdialect(方言)として、具象化された依存ライブラリが使用されるため可能である。これも完全に互換性があるわけではなく、Oracleの場合はIdentityクラスを使うことで代用される。
    • カラムの指定はqueryメソッド、WHERE句はfilterメソッド、ORDER BY句はorder_by句などSQLの構成が標準化されている。
  3. セキュリティ向上につながる。文字列結合によるSQLインジェクションを考慮が減る。
  4. 静的な関係を記述することが可能。特に外部キーや結合などの関係をあらわすことが可能。

デメリット

  1. 学習コストが高い。SQLに加えてORMの書き方を覚える必要がある。
  2. ORMを多用するとパフォーマンスが落ちる可能性あり。
  3. 複雑な結合は表現しづらい。
    • できなくはないが、素直にSQLを書いたほうが早い場合が多い(気がする)

  • ORMを使わない場合
from typing import NamedTuple
import pymysql.cursors

class HogeUser(NamedTuple):
    user_id:int
    user_name:str

connection = pymysql.connect(host='localhost',
                             user='user',
                             password='pass',
                             database='hoge',
                             cursorclass=pymysql.cursors.DictCursor)


with connection:
    with connection.cursor() as cursor:
        # Read a single record
        sql = "SELECT `user_id`, `user_name` FROM `hoge_user`"
        cursor.execute(sql)
        hoge_users = [HogeUser(user_id=row["user_id"], user_name=row["user_name"]) for row in cursor.fetchall()]
        print(hoge_users)
  • ORMを使う場合
from typing import Generator

from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.engine.base import Engine
from sqlalchemy.orm import (
    DeclarativeMeta,
    Session,
    declarative_base,
    sessionmaker,
)

# データベースエンジンを作成
EngineLocal: Engine = create_engine(
    "mysql+pymysql://user:pass@localhost:3306/hoge", echo=True
)


# セッションファクトリを作成
SessionLocal = sessionmaker(
    autocommit=False, autoflush=False, bind=EngineLocal
)

# モデルを定義するための基本となるBaseクラスを作成
Base: DeclarativeMeta = declarative_base()


# セッションを依存性として定義
def get_db() -> Generator[Session, None, None]:
    conn = EngineLocal.connect()
    db = SessionLocal(bind=conn)
    try:
        yield db
    finally:
        conn.close()
        db.close()


# ORM
class HogeUser(Base):
    __tablename__ = "hoge_user"
    user_id = Column(Integer(), primary_key=True, autoincrement="auto")
    user_name = Column(String(45))


gen = get_db()
for ses in gen:
    rows = ses.query(HogeUser).all()
    print(rows)

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA