잡동사니

반응형

질문

저는 데이터베이스 디자인에 익숙하지 않으며 학습 프로젝트를 위한 스키마를 설정하는 방법에 대한 조언을 사용할 수 있습니다. 아이디어는 Zork와 같은 텍스트 기반 어드벤처 게임과 같습니다.

Room 데이터베이스 테이블을 가져옵니다.

class Room(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(64), index=True)
    description = db.Column(db.String(512))

    north = db.Column(db.Integer, db.ForeignKey('room.id'))
    east = db.Column(db.Integer, db.ForeignKey('room.id'))
    west = db.Column(db.Integer, db.ForeignKey('room.id'))
    south = db.Column(db.Integer, db.ForeignKey('room.id'))

사용자가 방에있을 때 남쪽, 북쪽 등으로 갈 수 있습니다. 방은 서로 연결되어 있습니다. 외래 키를 테이블의 일부로 사용하는 것이이 문제를 해결하는 잘못된 방법이라고 생각합니다. 나는 postgres와 sqlalchemy를 사용하고 있습니다. 방이 데이터베이스에서 제거되는 경우 수동으로 관리하지 않고도 이러한 링크를 디자인하는 방법이 있다고 생각합니다.

links_table = db.Table('directions',
    db.Column('north_id', db.Integer, db.ForeignKey('room.id')),
    db.Column('west_id', db.Integer, db.ForeignKey('room.id')),
    db.Column('east_id', db.Integer, db.ForeignKey('room.id')),
    db.Column('south_id', db.Integer, db.ForeignKey('room.id')))

이것이 올바른 방향으로 나아가는 단계가 될까요? 아니면 north_to_south, south_to_north 테이블이 필요합니까?

 north_to_south = db.Table('north_to_south',
    db.Column('north_id', db.Integer, db.ForeignKey('room.id')),
    db.Column('south_id', db.Integer, db.ForeignKey('room.id')))

 

답변1

SQL DB가 그러한지도를 저장하는 작업에 적합한 도구인지 확실하지 않지만 연결 테이블 또는 SQLAlchemy 용어로 연결 객체 패턴. (src_id, dst_id, dir) 과 같은 연관 테이블을 만들어 모델을 더욱 유연하게 만들 수 있습니다.

class Direction(db.Model):
    # Let the DB cascades remove directions, if a room is deleted.
    src_id = db.Column(db.ForeignKey('room.id', ondelete='CASCADE'),
                       primary_key=True)
    dst_id = db.Column(db.ForeignKey('room.id', ondelete='CASCADE'),
                       primary_key=True)
    # A point for further normalization, create a table for enumerating
    # direction labels.
    dir = db.Column(db.String(16), primary_key=True)

    # Since this model has multiple foreign keys referencing the same
    # target model, the relationships must be told which one to use.
    src = db.relationship('Room', foreign_keys=[src_id],
                          back_populates='directions')
    dst = db.relationship('Room', foreign_keys=[dst_id])

이렇게하면 또 다른 멋진 SQLAlchemy 기능을 사용할 수 있습니다. 관련 객체를 사전으로 수집 :

from sqlalchemy.orm.collections import attribute_mapped_collection

class Room(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(64), index=True)
    description = db.Column(db.String(512))

    directions = db.relationship(
        'Direction', collection_class=attribute_mapped_collection('dir'),
        foreign_keys='[Direction.src_id]', passive_deletes=True,
        back_populates='src')

길 찾기를 채우는 것은 약간의 귀찮은 일입니다.

In [33]: r1 = Room(title='r1')

In [34]: r2 = Room(title='r2')

In [35]: r3 = Room(title='r3')

In [36]: r4 = Room(title='r4')

In [37]: r5 = Room(title='r5')

In [39]: for dir_, dst in zip(['north', 'east', 'south', 'west'],
    ...:                      [r2, r3, r4, r5]):
    ...:     r1.directions[dir_] = Direction(dir=dir_, dst=dst)
    ...:     

In [40]: db.session.add(r1)

In [41]: db.session.commit()

방향을 키로 사용하고 Direction 생성자에 전달해야한다는 점에서 약간 중복됩니다. 이상적으로는 Direction 을 전혀 다룰 필요가 없습니다. 이는 연결 프록시 를 사용하여 수행 할 수 있습니다.

from sqlalchemy.ext.associationproxy import association_proxy

class Room(db.Model):
    ...
    dirs = association_proxy(
        'directions', 'dst',
        creator=lambda dir_, dst: Direction(dir=dir_, dst=dst))

그 후에 길 찾기를 추가하는 것이 더 쉽습니다.

In [87]: r6 = Room(title='r6')

In [88]: r2.dirs['up'] = r6

이렇게하면 변수가 지정된 길 찾기에 쉽게 액세스 할 수 있습니다.

In [79]: where_to = input()
west

In [80]: r1.dirs[where_to]
Out[80]: <__main__.Room at 0x7fa652e4a320>



 

 

 

 

출처 : https://stackoverflow.com/questions/49217231/many-to-many-cardinal-direction-database-scheme-design

반응형

이 글을 공유합시다

facebook twitter googleplus kakaoTalk kakaostory naver band