Python的魔法ORM --《PonyORM教程》 3 實(shí)體繼承

實(shí)體繼承就是我們平時(shí)編程時(shí)用到的類的繼承。不過(guò)由于ORM牽扯到數(shù)據(jù)在數(shù)據(jù)庫(kù)中的存儲(chǔ)問(wèn)題,所以情況要復(fù)雜一些,常見(jiàn)的對(duì)于有繼承關(guān)系的類處理方法一般是以下三種:

  1. 單表繼承模式 父類和子類的所有字段都保存在同一張表里。
  2. 具體表繼承模式 父類和子類的所有字段分別保存在自己的表里
  3. 聯(lián)表繼承模式 父類的表記錄公共字段,后代類的表記錄自己的專用字段

django使用的是聯(lián)表繼承模式,sqlalchemy作為重量級(jí)的ORM實(shí)現(xiàn)了全部的3種繼承模式(牛逼啊!??????),而pony選擇的是單表繼承模式。三種模式的優(yōu)缺點(diǎn)如下:

單表繼承模式

優(yōu)點(diǎn)

  • 由于所有的記錄都放在一張表里,所以查詢對(duì)象的時(shí)候,無(wú)需聯(lián)表查詢,速度快
  • 有關(guān)系的父子類之間不存在數(shù)據(jù)同步更新問(wèn)題。
  • 冗余字段少。

缺點(diǎn)

  • 不同類的數(shù)據(jù)保存在一起,不方便剝離某個(gè)單獨(dú)的類。
  • 由于不同的子類可能有不同的字段定義,導(dǎo)致表中出現(xiàn)大量的Null值,雖然這并不會(huì)占用大量的空間,但是對(duì)于某些類型的強(qiáng)迫癥患者來(lái)說(shuō),這可能是一個(gè)不能忍的缺陷。
  • 由于所有的類的字段的定義都保存在一張表內(nèi),在某種極端的情況下,這可能會(huì)達(dá)到數(shù)據(jù)庫(kù)的限制。不過(guò)一般情況下,這種限制都很高。比如mysql的最大列限制是4096,最大行尺寸是65,535bytes
具體表繼承模式

優(yōu)點(diǎn)

  • 不同的類都有自己專用的表,無(wú)需聯(lián)表查詢,速度快。
  • 每個(gè)類的數(shù)據(jù)獨(dú)立存儲(chǔ)自己的表中,方便剝離, 靈活性高。

缺點(diǎn)

  • 冗余字段多,浪費(fèi)空間。
  • 有關(guān)系的父子類之間可能存在數(shù)據(jù)同步更新問(wèn)題。(依模型設(shè)計(jì)而定),要小心處理。

聯(lián)表繼承模式

優(yōu)點(diǎn)

  • 冗余字段少且沒(méi)有額外的Null值
  • 有關(guān)系的父子類之間不存在數(shù)據(jù)同步更新問(wèn)題。

缺點(diǎn)

  • 子類的數(shù)據(jù)需要聯(lián)表查詢,效率低,這也是這種模式最大的問(wèn)題。
  • 不同類的數(shù)據(jù)雖然保存在不同的表中,但由于每個(gè)表保存的都是部分?jǐn)?shù)據(jù)所以依然不方便剝離某個(gè)單獨(dú)的類。

演示一下

class Person(db.Entity):
    """人"""
    _table_ = "person"
    name = Required(str, max_len=40)
    # class_type = Discriminator(str)  # 定義一個(gè)鑒別器字段
class Customer(Person):
    """顧客"""
    member_level = Required(int, size=8, default=0)  # 會(huì)員卡級(jí)別
    # _discriminator_ = "customer" 鑒別標(biāo)識(shí)


class Sales(Person):
    """銷售員"""
    performance = Required(float, default=0.0)  # 銷售業(yè)績(jī)
    # _discriminator_ = "sales" 鑒別標(biāo)識(shí)


if __name__ == "__main__":
    db.drop_table(table_name="person", if_exists=True, with_all_data=True)  # 刪除表,演示實(shí)體聲明時(shí)用于快速清除舊表
    db.generate_mapping(create_tables=True)  # 生成實(shí)體,表和映射關(guān)系
    with db_session:
        person = Person(name="約翰")  # 創(chuàng)建一個(gè)Person對(duì)象的實(shí)例
        customer = Customer(name="瑪麗", member_level=1)  # 創(chuàng)建一個(gè)Customer對(duì)象的實(shí)例
        sales = Sales(name="喬治", performance=3000)  # 創(chuàng)建一個(gè)Sales對(duì)象的實(shí)例
        flush()  # 刷新,這里的刷新是為了讓剛才創(chuàng)建的對(duì)象分配到id
        print("所有人員信息:" + " ".join([x for x in select(x.name for x in Person)]))  
        print("所有客戶信息:" + " ".join([x for x in select(x.name for x in Customer)]))  
        print("所有銷售員信息:" + " ".join([x for x in select(x.name for x in Sales)]))  
    pass

說(shuō)明

  • 只能在頂級(jí)的父類中定義表名,子類表中不可重新定義表名
  • 父類中可以自定義一個(gè)鑒別器字段,用于區(qū)別不同的類,定義的方法上面代碼,要求是
    只要是Discriminator的實(shí)例就好了,可以是字符串,也可以是其他類型,不過(guò),當(dāng)不是字符串的時(shí)候,子類必須定義discriminator字段(鑒別標(biāo)識(shí),用于確認(rèn)類的數(shù)據(jù)在表中的唯一性),鑒別器字段不是必須定義的,系統(tǒng)會(huì)提供默認(rèn)值classtype
  • 子類中可以定義discriminator(鑒別標(biāo)識(shí))字段,用于確認(rèn)字段的歸屬。定義時(shí),必須和頂級(jí)父類中定義的Discriminator實(shí)例的類型一致,鑒別標(biāo)識(shí)字段不是必須定義的,系統(tǒng)會(huì)提把類名作為默認(rèn)值。

執(zhí)行結(jié)果

Connected to pydev debugger (build 192.6603.34)
所有人員信息:約翰 瑪麗 喬治
所有客戶信息:瑪麗
所有銷售員信息:?jiǎn)讨?
Process finished with exit code 0

你可以注意到,由于Customer和Sales是Person的子類,所以在添加Customer和Sales實(shí)例時(shí),Person也增加了對(duì)應(yīng)的實(shí)例

屏幕截圖.png

請(qǐng)注意classtype是鑒別器字段,這里使用了默認(rèn)值類名作鑒別標(biāo)識(shí)。

索引

  1. Python的魔法ORM --《PonyORM教程》 1.連接,聲明和查詢
  2. Python的魔法ORM --《PonyORM教程》 2 實(shí)體關(guān)系
  3. Python的魔法ORM --《PonyORM教程》 3 實(shí)體繼承
  4. Python的魔法ORM --《PonyORM教程》 4 高級(jí)定義和連接查詢
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容