2012-01-12 22 views
11

Bu ORM kullandığım ilk kez, bu işlemek için en iyi yolu emin değilim. sqlalchemy bire çok ilişkide çocuk ekle

class Parent(Base): 
    __tablename__ = 'Parent' 

    name = Column(String(50)) 
    gid = Column(String(16), primary_key = True) 
    lastUpdate = Column(DateTime) 

    def __init__(self,name, gid): 
     self.name = name 
     self.gid = gid 
     self.lastUpdate = datetime.datetime.now() 


class Child(Base): 
    __tablename__ = 'Child' 

    id = Column(Integer, primary_key = True) 
    loc = Column(String(50)) 
    status = Column(String(50)) 

    parent_gid = Column(String(16), ForeignKey('Parent.gid')) 

    parent = relationship("Parent", backref=backref('children')) 

Şimdi, güncellemeler ağ üzerinden geliyor: Her Veli birçok Children olabilir bire çok ilişki var. Bir güncelleştirme geldiğinde, uygun Üst Satırı (UPUpdate sütunu güncelle) ve INSERT yeni alt satırları veritabanına GÜNCELLEME istiyorum. Bunu ORM ile nasıl yapacağımı bilmiyorum. İşte benim başarısız girişimi:

engine = create_engine('sqlite+pysqlite:///file.db', 
         module=dbapi2) 
Base.metadata.create_all(engine) 
session = sessionmaker(bind=engine)() 

def addChildren(parent): 
    p = session.query(Parent).filter(Parent.gid == p1.gid).all() 
    if len(p) == 0: 
     session.add(p1) 
     session.commit() 
    else: 
     updateChildren = parent.children[:] 
     parent.chlidren = [] 
     for c in updateChildren: 
      c.parent_gid = parent.gid 

     session.add_all(updateChildren) 
     session.commit() 

if __name__ == '__main__': 

    #first update from the 'network' 
    p1 = Parent(name='team1', gid='t1') 
    p1.children = [Child(loc='x', status='a'), Child(loc='y', status='b')] 
    addChildren(p1) 

    import time 
    time.sleep(1) 

    #here comes another network update 
    p1 = Parent(name='team1', gid='t1') 
    p1.children = [Child(loc='z', status='a'), Child(loc='k', status='b')] 
    #this fails 
    addChildren(p1) 

Başlangıçta birleştirme yapmaya çalıştı, ama o eski çocuk ebeveynin (yabancı kimlikleri null ayarlanmış) ile ilişkisi kaldırılacaktır neden oldu. Buna ORM ile yaklaşmanın en iyi yolu nedir? Teşekkür

DÜZENLEME

Ben güncellemeler ağ üzerinden geldiğinizde gerçekten tamamen yeni nesneler yaratmak için mantıklı değil sanırım. Sadece uygun ebeveyn için oturumu sorgulamalıyım, sonra gerekirse yeni çocukları yaratmalı ve birleştirmeliyim? Örneğin.

def addChildren(pname, pid, cloc, cstat): 
    p = session.query(Parent).filter(Parent.gid == pid).all() 
    if len(p) == 0: 
     p = Parent(pname, pid) 
     p.children = [Child(loc=cloc, status=cstat)] 
     session.add(p) 
     session.commit() 
    else: 
     p = p[0] 
     p.children.append(Child(loc=cloc, status=cstat)) 
     session.merge(p) 
     session.commit() 

cevap

24

Haklısınız - aynı üst öğeyi iki kez oluşturmamalısınız. Çocukları eklemek açısından ... iyi, sadece onları eklemeniz gerekiyor ve mevcut olanları umursamıyorsunuz ... Böylece düzenlenmiş kodunuz işi iyi yapmalı. Bunu daha kısa ve gerçi daha okunabilir yapabilirsiniz: Bu yol

def addChildren(pname, pid, cloc, cstat): 
    p = session.query(Parent).get(pid) # will give you either Parent or None 
    if not(p): 
     p = Parent(pname, pid) 
     session.add(p) 
    p.children.append(Child(loc=cloc, status=cstat)) 
    session.commit() 

dezavantaj yeni Çocuk eklendi ve daha sonra veritabanına kaydedilir önce varolan Veli Çocukların Bütün koleksiyon belleğe yüklenecek olmasıdır. Bu (çok ve her ebeveyn için çocukların sayısındaki artış) durumda, o zaman lazy='noload' yararlı olabilir:

parent = relationship("Parent", backref=backref('children', lazy='noload')) 

Bu dramatik ekler hızını artırmak olabilir, ancak bu durumda p.children olacak erişim Hiçbir zaman, mevcut nesneleri veritabanından yüklemez. Bu senaryolarda başka bir ilişki tanımlamak yeterlidir. Bu durumlarda Building Query-Enabled Properties'u kullanmayı tercih ederim, bu nedenle, bir nesne eklemek için yalnızca bir ve bir tek özelliği ile sonuçlanırsınız; bu, sistemin farklı bölümleri tarafından sıklıkla kullanılan kalıcı sonuçları sorgulamak için yalnızca .

+1

'p.children.extend ([list_of_children])' işlevini kullanabileceğiniz çocukların listesini eklemek için, hayır? – aganders3

+1

evet, tabi. Aslında, "Ana" nın verilen "pid" için var olduğundan eminsek ve eldeki görev sadece "Çocuk (ren)" yi depolamaktan eminseydi, yapabilecekler ilişkiyi yüklememektir, ancak doğrudan Parent_gid' için FK değeri: 'session.add (Child (loc = cloc, status = cstat, parent_gid = pid)), bu durumda, 'tembel =" noload "ile ilişkiyi kandırmaya bile gerek yoktur, Çünkü kod – van

+0

ilişkisini kullanmayacaktır. Aynı senaryodaki çocuğu nasıl güncelleyeceğinizi de gösterir misiniz? –

İlgili konular