엔지니어링

ORM 간단하게 알아보기

당나귀🐴 2022. 4. 5. 02:45

ORM (Object_Relational Mapper)

장점

  • 현재 사용하고 있는 언어만 사용해도 됨
  • 데이터베이스 시스템으로부터 분리가 됨
  • 직접 작성하는 SQL 쿼리문이 없고 더 높은 성능의 SQL 쿼리문을 작성할 수 있습니다.

단점

  • 데이터베이스와 바로 연결하는 것보다 초기설정이 더 많아지거나 복잡해질 수 있습니다.
  • 내부 작동에 대한 충분한 이해가 없는 경우 해결이 힘들 수 있습니다.
  • 데이터베이스에 직접 쿼리문을 보내는 것이 아니기 떄문에 성능 저하가 발생합니다.

SQLAlchemy (ORM 의 기능을 제공하는 Python 라이브러리)

Core

  • 데이터베이스와 상호작용

엔진

from sqlalchemy import create_engine

engine = create_engine("데이터베이스 주소")

#engine = create_engine("sqlite:///:memory:")

# 주위
# - :// 다음에 / 가 하나가 오면 현재 디렉토리부터 상대적인 경로, // 처럼 두개가 있다면 절대적인 경로
# - :memory: -> 메모리에서 임시적인 데이터베이스를 사용한다는 뜻

매핑(Mappaing)

  • 데이터베이스의 구조와 코드상의 구조를 연결하는 것
  • 특정 테이블이 데이터베이스 상에 존재한다면 코드 상에서도 해당 테이블과 연결될 수 있도록 테이블을 구현하는 것

declarative_base()

  • base class 를 리턴
  • base class 를 상속받은 클래스는 자동으로 ORM이랑 연결지어서 사용됨
CREATE TABLE user (
    id INTEGER PRIMARY KEY,
    name STRING,
    age INTEGER
)

from sqlalchemy.orm import declarative_base

base = declarative_base()

from sqlalchemy import Column, Integer, String

class User(base):
    __tablename__ = 'user'

    id = Column(String, primary_key=True)
    name = Column(String)
    age = Column(Integer)

    # id = Column(name = 'id', Integer, primary_key=True)
    # name = Column(name = 'name', String)
    # age = Column(name = 'age', Integer)


    def __repr__(self):
        return f"USER id : {self.id}, name : {self.name}, age : {self.age}"
  • 클래스의 이름을 소문자로 변경한 테이블과 매핑
  • __tablename__을 사용해도 좋지만, 클래스 이름으로 매핑시키는게 더 좋아보임

매핑한 내용을 데이터베이스와 연결 ( 스키마 생성 )

base.metadata.create_all(engine)

세션 (Session)

from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)

# 후에 연결도 가능
# Session = sessionmaker()
# Session.configure(bind=engine)
  • 이후 세션을 통한 작업

Create : 데이터 추가

ed_user = User(id='ed', name='Ed Jones', age=19)
Session.add(ed_user)

<!-- Session.add_all([
    User(id='ed', name='Ed Jones', age=19),
    User(id='wd', name='Wendy', age=19),
    User(id='fd', name='Fred', age=19),
]) -->

조회

 our_user = session.query(User).filter_by(name='ed').first()

#  >> ed_user == our_user (값 비교)
#  >> TRUE
#  >> ed_user is our_user (주소 비교)
#  >> TRUE
for instance in session.query(User).order_by(User.id):
    print(instance.name, instance.fullname)

for id, name in session.query(User.id, User.name):
    print(id, name)

for row in session.query(User, User.Uname).all():
    print(row.User, row.name)

#LIMIT
for u in session.query(User).order_by(User.id)[1:2+1]:
    print(u)

# Filter
for name in session.query(User.name).filter_by(name='Ed Jones'):
    print(id)
# Filter : SQL 보다 유연하게 사용가능 ( Python 연산자 모두 가능)
for name in session.query(user.name).filter_by(User.name=='Ed Jones')

for user in session.query(User).filter(User.id=='ed')\
.filter(User.name=='Ed Jones')

for user in session.query(User).filter(User.name.like('%ed%'))

세션을 데이터베이스에 적용하고 싶을때

Session.commit()