2013-06-03 2 views
2

를 새로 고칩니다. 종종 세션에서 Foo 객체를 분리하고 값과 Bar의 값을 계속 사용합니다. 때때로 Foo의 상태 필드를 업데이트해야합니다. 이 경우 새 세션을 만들고 foo 객체를 세션에 추가하고 커밋합니다. 커밋 후에 Foo 객체와 연결된 Bar 객체는 무효화되지만 Foo 객체의 커밋의 암시 적 새로 고침에 의해 다시로드되지 않습니다. Foo 객체를 세션에서 다시 분리하면 Bar 객체는 더 이상 사용할 수 없습니다. 내가 해결할 수있는 유일한 방법은 foo를 커밋 한 후 명시 적으로 막대 객체를로드하는 것입니다.SQLAlchemy의 열망로드

예 워크 플로우는 :

session = Session() 
foo = session.query(Foo).get(id) <-- foo.bar is automatically eager loaded 
session.close() 
.... 
session = Session() 
session.add(foo) 
foo.status = 'done' 
session.commit()  <-- foo is commited and refreshed, foo.bar is not 
session.refresh(foo) <-- same here, foo.bar is not loaded 
#foo.bar    <-- only explicit eager loading foo.bar here works 
session.close() 
.... 
foo.bar    <-- error if not explicitly eager loaded 

나는 객체와 같은 그 작은 바의 몇 가지에 대해이 설정을 사용하고 싶습니다. foo.bar 객체를 항상 명시 적으로 다시로드하는 것을 기억하도록 요청하면 오류가 발생하기 쉽습니다. 그래서 내 질문은 : 쿼리(), 커밋() (암시 적 새로 고침) 또는 (명시 적) 새로 고침() 수 모든 상황에서 foo.bar로드 열망 수 있습니까?

답변

2

"커밋()"은 "새로 고침"이 아닙니다. 실제로 모든 데이터가 만료되므로 모든 매핑 된 속성이 더 이상 foo.__dict__에 나타나지 않습니다. 암시 적 새로 고침은 해당 속성을 다시 터치 할 때 발생합니다. 커밋 후 트랜잭션 간 동기화가 필요없는 많은 응용 프로그램의 경우 expire_on_commit=FalseSession 내에 설정하는 것이 가장 일반적인 방법이므로 가장 암시적인 워크 플로가 될 수 있습니다.

다음 물건, session.refresh(foo)은 구성된 열렬한 로더를 사용하여 bar을로드합니다. foo.bar이로드되지 않은 이유를 잘 모르겠습니다.이 기능은 적어도 버전 0.5 이상으로 돌아갑니다. 간단한 테스트를 확인 :

from sqlalchemy import * 
from sqlalchemy.orm import * 
from sqlalchemy.ext.declarative import declarative_base 

Base = declarative_base() 

class Foo(Base): 
    __tablename__ = 'foo' 
    id = Column(Integer, primary_key=True) 
    status = Column(String) 
    barId = Column(Integer, ForeignKey("bar.id")) 
    bar = relationship("Bar", lazy="joined") 

class Bar(Base): 
    __tablename__ = 'bar' 
    id = Column(Integer, primary_key=True) 

e = create_engine("sqlite://", echo=True) 
Base.metadata.create_all(e) 

s = Session(e) 

s.add(Foo(id=1, bar=Bar())) 
s.commit() 

f1 = s.query(Foo).get(1) 
f1.status = 'done' 
s.commit() 

assert 'bar' not in f1.__dict__ 
s.refresh(f1) 
assert 'bar' in f1.__dict__ 
s.close() 

assert f1.bar.id == 1 

다음 것은, SQLAlchemy의이 매핑 된 객체가 지속적인 데이터베이스 트랜잭션에 대한 프록시를 나타내는 일반적인 이유에 대한 자신의 "분리 된"상태에서 개체를 사용하여 낙담한다. 그래서 트랜잭션이 끝나면 모든 데이터가 만료됩니다. 개인적으로, 나는 분리 된 상태에서 물체를 사용해야한다는 정당한 이유가 있다고 생각하지 않는다. detachment는 주로 객체를 다른 세션으로 옮기고 캐시에 저장하는 용도로 사용됩니다. 그러나 우리는 어떤 경우에도 분리 된 사용 패턴에 의존하는 많은 사용자를 보유하고 있으며 합리적인 수준으로 지원할 수 있는지 확인 했으므로 걱정하지 않을 것입니다.

+0

내 특정 설정에서's.commit()'은 foo 객체에서 bar를 사용하지 않고 (내가 직접 attr을 건드린 다) 선택을합니다. 이유가 확실하지 않습니다. 나는 암시 적으로 당신이 지적한대로 암시 적으로 새로 고침을 위해 그것을 취했습니다. 나는 당신의 작은 데모로 이것을 미리 준비 할 수 없다. 열정적 인 로딩은 명백한's.refresh (foo)'로 작동합니다. 나는 그걸 어떻게 든 놓쳤다. 나는 여전히 SQLAlchemy를 많이 배우고 실험하고있다. – dieterg

+0

SQLAlchemy는 "분리 된"상태의 개체를 사용하지 않으려 고합니다. My Foo 객체는 여러 HTTP 요청을 처리하며 요청이 끝나면 항상 orm 세션을 닫습니다. foo 객체를 1/100 만 업데이트하면됩니다. 다른 99 개는 데이터를 사용합니다. 그렇다면 어떤 디자인을 권하고 싶습니까? 1) Foo와 Bar의 데이터를 nonm 객체와 requery에 복사해야합니다. 2) Foo를 업데이트/새로 고침 할 필요가 없더라도 새로운 orm 세션을 엽니 다. 3) ... – dieterg

+1

일반적으로 웹 응용 프로그램은 모든 요청에 ​​필요한 모든 데이터를로드합니다. Foo 객체를 요청 번호 1 번에로드하면 6 시간 후에 요청 번호 2가 나오고 6 시간 동안 메모리에 "Foo"객체를 저장 했습니까? 그들이 최신 정보를 어떻게 알 수 있습니까? 이것은 실제로 캐싱 패턴입니다.SQLAlchemy에서 캐싱을 권장하는 이유는 개체가 각 요청에 대해 새 Session에 다시 첨부되거나 병합된다는 것입니다. [dogpile caching] (http://docs.sqlalchemy.org/en/rel_0_8/orm/examples.html#dogpile-caching) 권장 설계 지침. – zzzeek