Fix: Composite primary key with auto-increment value returns 0 after insert (#6127)
* Fix #4930 workaround for databases that support auto-increment in composite primary key. * Add test for composite key with auto-increment. * schema.go: use field.AutoIncrement instead of field.TagSettings["AUTOINCREMENT"], add test to check autoincrement:false create_test.go: remove unused code: drop table CompositeKeyProduct --------- Co-authored-by: Jinzhu <wosmvp@gmail.com>
This commit is contained in:
		
							parent
							
								
									1643a36260
								
							
						
					
					
						commit
						ed474152b1
					
				| @ -221,8 +221,18 @@ func ParseWithSpecialTableName(dest interface{}, cacheStore *sync.Map, namer Nam | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if schema.PrioritizedPrimaryField == nil && len(schema.PrimaryFields) == 1 { | 	if schema.PrioritizedPrimaryField == nil { | ||||||
| 		schema.PrioritizedPrimaryField = schema.PrimaryFields[0] | 		if len(schema.PrimaryFields) == 1 { | ||||||
|  | 			schema.PrioritizedPrimaryField = schema.PrimaryFields[0] | ||||||
|  | 		} else if len(schema.PrimaryFields) > 1 { | ||||||
|  | 			// If there are multiple primary keys, the AUTOINCREMENT field is prioritized
 | ||||||
|  | 			for _, field := range schema.PrimaryFields { | ||||||
|  | 				if field.AutoIncrement { | ||||||
|  | 					schema.PrioritizedPrimaryField = field | ||||||
|  | 					break | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for _, field := range schema.PrimaryFields { | 	for _, field := range schema.PrimaryFields { | ||||||
|  | |||||||
| @ -293,3 +293,44 @@ func TestEmbeddedStructForCustomizedNamingStrategy(t *testing.T) { | |||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestCompositePrimaryKeyWithAutoIncrement(t *testing.T) { | ||||||
|  | 	type Product struct { | ||||||
|  | 		ProductID    uint `gorm:"primaryKey;autoIncrement"` | ||||||
|  | 		LanguageCode uint `gorm:"primaryKey"` | ||||||
|  | 		Code         string | ||||||
|  | 		Name         string | ||||||
|  | 	} | ||||||
|  | 	type ProductNonAutoIncrement struct { | ||||||
|  | 		ProductID    uint `gorm:"primaryKey;autoIncrement:false"` | ||||||
|  | 		LanguageCode uint `gorm:"primaryKey"` | ||||||
|  | 		Code         string | ||||||
|  | 		Name         string | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	product, err := schema.Parse(&Product{}, &sync.Map{}, schema.NamingStrategy{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("failed to parse product struct with composite primary key, got error %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	prioritizedPrimaryField := schema.Field{ | ||||||
|  | 		Name: "ProductID", DBName: "product_id", BindNames: []string{"ProductID"}, DataType: schema.Uint, PrimaryKey: true, Size: 64, HasDefaultValue: true, AutoIncrement: true, TagSettings: map[string]string{"PRIMARYKEY": "PRIMARYKEY", "AUTOINCREMENT": "AUTOINCREMENT"}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	product.Fields = []*schema.Field{product.PrioritizedPrimaryField} | ||||||
|  | 
 | ||||||
|  | 	checkSchemaField(t, product, &prioritizedPrimaryField, func(f *schema.Field) { | ||||||
|  | 		f.Creatable = true | ||||||
|  | 		f.Updatable = true | ||||||
|  | 		f.Readable = true | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	productNonAutoIncrement, err := schema.Parse(&ProductNonAutoIncrement{}, &sync.Map{}, schema.NamingStrategy{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("failed to parse productNonAutoIncrement struct with composite primary key, got error %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if productNonAutoIncrement.PrioritizedPrimaryField != nil { | ||||||
|  | 		t.Fatalf("PrioritizedPrimaryField of non autoincrement composite key should be nil") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | |||||||
| @ -548,6 +548,35 @@ func TestFirstOrCreateRowsAffected(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func TestCreateWithAutoIncrementCompositeKey(t *testing.T) { | ||||||
|  | 	type CompositeKeyProduct struct { | ||||||
|  | 		ProductID    int `gorm:"primaryKey;autoIncrement:true;"` // primary key
 | ||||||
|  | 		LanguageCode int `gorm:"primaryKey;"`                    // primary key
 | ||||||
|  | 		Code         string | ||||||
|  | 		Name         string | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := DB.AutoMigrate(&CompositeKeyProduct{}); err != nil { | ||||||
|  | 		t.Fatalf("failed to migrate, got error %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	prod := &CompositeKeyProduct{ | ||||||
|  | 		LanguageCode: 56, | ||||||
|  | 		Code:         "Code56", | ||||||
|  | 		Name:         "ProductName56", | ||||||
|  | 	} | ||||||
|  | 	if err := DB.Create(&prod).Error; err != nil { | ||||||
|  | 		t.Fatalf("failed to create, got error %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	newProd := &CompositeKeyProduct{} | ||||||
|  | 	if err := DB.First(&newProd).Error; err != nil { | ||||||
|  | 		t.Fatalf("errors happened when query: %v", err) | ||||||
|  | 	} else { | ||||||
|  | 		AssertObjEqual(t, newProd, prod, "ProductID", "LanguageCode", "Code", "Name") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func TestCreateOnConfilctWithDefalutNull(t *testing.T) { | func TestCreateOnConfilctWithDefalutNull(t *testing.T) { | ||||||
| 	type OnConfilctUser struct { | 	type OnConfilctUser struct { | ||||||
| 		ID     string | 		ID     string | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Truong Nguyen
						Truong Nguyen