gorm中的數據庫完整性約束(1)


寫這篇文章的初衷是由於自己一直對數據庫的一些基本知識瞭解得不是很透徹,加上gorm文檔中對數據庫完整性描述簡直讓人摸不着頭腦。趁着這個機會,我們來整合一下這些知識,爲後面更深入地使用gorm打下基礎。其次,可能許多同學在閱讀gorm的文檔時,也有同樣的疑惑,希望大家一起討論,共同進步。

溫故而知新一

超鍵:是一個或者多個屬性的集合,這些屬性的組合可以使我們在一個關係中唯一地標識一個元組。
候選鍵: 去掉冗餘屬性之後的最小超鍵。
主鍵:用來標示某個元組在它所存在的關係中是是唯一的。通俗來說,主鍵是介於超鍵和候選鍵之間的key。

主鍵約束(非空且唯一)

首先我們來看看數據庫完整性規範中的第一條,實體完整性約束:每個表有且僅有一個主鍵,每一個主鍵值必須唯一,而且不允許爲“空”(NULL)或重複。我們首先對Product結構體進行自動遷移,Debug方法可以幫助我們打印sql語句,調試起來很方便。

var (
	db  *gorm.DB
	err error
)

type Product struct {
	gorm.Model  // grom.Model是gorm預定義的結構,用於實現軟刪除 
	Code  string `gorm:"primary_key"`
	Price uint	
}

//type Model struct {
//    ID uint `gorm:"primary_key"`
//    CreatedAt time.Time
//    UpdatedAt time.Time
//    DeletedAt *time.Time `sql:"index"`
//}

func main() {
	db, err := gorm.Open("postgres", "host=localhost user=testuser dbname=testdb sslmode=disable password=123456")
	defer db.Close()
	fmt.Println(err)
	if err == nil {
		db.Debug().AutoMigrate(&Product{})
	}
	
//CREATE TABLE "products" ("id" serial,"created_at" timestamp with time zone,"updated_at" timestamp with time zone,"deleted_at" timestamp with time zone,"code" text,"price" integer , PRIMARY KEY ("id","code"))  
	
//CREATE INDEX idx_products_deleted_at ON "products"(deleted_at)  

從 sql PRIMARY KEY (“id”,“code”)) 中,我們可以知道,在這次數據庫遷移中,我們定義了聯合主鍵。因此,我們可以下定論,Gorm實現了對數據庫實體完整性支持,即可以支持字段主鍵,也可以支持聯合主鍵。在這裏,有同學可能覺得這是很稀鬆平常的事情,但是當你往下看,或許又是另一翻感悟。

在這裏我們可以順帶提一下ORM中的命名規範,爲工程項目建立規範標準,也是一件很重要的事情:

單數變複數 駝峯式的命名方法
規範 模型名統一爲單數,對應的數據庫表名爲複數 若結構體名由多個單詞組成,對應的數據表將使用下劃線
示例 Book(模型名稱) —> books(數據表名) BookClub(模型類名) —> book_clubs(數據表名)

溫故而知新二

外鍵: 一個關係模式(r1)可能在它的屬性中包含另一個關係模式(r2)的主鍵,這個屬性在r1上被稱爲外鍵,關係r1被稱爲外鍵依賴的參照關係,r2叫做外鍵依賴的被參照關係

關聯外鍵: 這個術語的英文叫AssociationForeignKey,可以用於指定被參照關係中(r2)中特定字段。

外鍵約束

Belongs To

首先我們來看看gorm文檔中belongs to關係。belongs_to 關聯創建兩個模型之間一對一的關係,product belongs to user,聲明所在的模型實例屬於另一個模型的實例。 在我們下面聲明的例子中,有商品和用戶兩個模型,而每個商品只能指定一個用戶。

type Product struct {
    Code string  `gorm:"primary_key"`
    Price uint
    UserID uint 
    User User   // 用於聲明 Product belongs to User,
    gorm.Model
}

type User struct {
    gorm.Model
    Code string  `gorm:"primary_key"`
    Name string
}

func main() {
	db, err := gorm.Open("postgres", "host=localhost user=testuser dbname=testdb sslmode=disable password=123456")
	defer db.Close()
	fmt.Println(err)
	if err == nil {
		db.Debug().AutoMigrate(&User)AutoMigrate(&Product{})
	}
}	
//CREATE TABLE "products" ("id" serial,"created_at" timestamp with time zone,"updated_at" timestamp with time zone,"deleted_at" timestamp with time zone,"code" text,"price" integer , PRIMARY KEY ("id","code")) 

//CREATE INDEX idx_products_deleted_at ON "products"(deleted_at) 

我們可以在sql中發現,Product結構體中的成員User並無實際用處,其作用只是用於表示 product belongs to user的關聯關係。其次,此次遷移並沒有添加任何的外鍵約束。

然後在main方法中加入這個語句,

user := User{Code: "test", Name: "test"}
db.Debug().Create(&user)
// INSERT  INTO "users" ("created_at","updated_at","deleted_at","code","name") VALUES ('2019-04-25 23:40:45','2019-04-25 23:40:45',NULL,'test','test') 
db.Debug().Model(&user).Related(&product)
//  SELECT * FROM "products"  WHERE "products"."deleted_at" IS NULL AND (("user_id" = 5))  

Has one

has_one 關聯也建立兩個模型之間的一對一關係,但語義和結果有點不一樣。這種關聯表示模型的實例包含或擁有另一個模型的實例。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章