issue_50 #57
@@ -0,0 +1,103 @@
 | 
				
			|||||||
 | 
					# 设备与任务多对多关联模型设计
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 需求背景
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					用户需要为系统中的“设备”和“任务”增加多对多关联,即一个设备可以执行多个任务,一个任务可以被多个设备执行。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 现有模型分析
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### `internal/infra/models/device.go`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`Device` 模型定义:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					type Device struct {
 | 
				
			||||||
 | 
						gorm.Model
 | 
				
			||||||
 | 
						Name             string `gorm:"not null" json:"name"`
 | 
				
			||||||
 | 
						DeviceTemplateID uint   `gorm:"not null;index" json:"device_template_id"`
 | 
				
			||||||
 | 
						DeviceTemplate   DeviceTemplate `json:"device_template"`
 | 
				
			||||||
 | 
						AreaControllerID uint   `gorm:"not null;index" json:"area_controller_id"`
 | 
				
			||||||
 | 
						AreaController   AreaController `json:"area_controller"`
 | 
				
			||||||
 | 
						Location         string `gorm:"index" json:"location"`
 | 
				
			||||||
 | 
						Properties       datatypes.JSON `json:"properties"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### `internal/infra/models/plan.go`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`Task` 模型定义:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					type Task struct {
 | 
				
			||||||
 | 
						ID        int `gorm:"primarykey"`
 | 
				
			||||||
 | 
						CreatedAt time.Time
 | 
				
			||||||
 | 
						UpdatedAt time.Time
 | 
				
			||||||
 | 
						DeletedAt gorm.DeletedAt `gorm:"index"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						PlanID         uint           `gorm:"not null;index" json:"plan_id"`
 | 
				
			||||||
 | 
						Name           string         `gorm:"not null" json:"name"`
 | 
				
			||||||
 | 
						Description    string         `json:"description"`
 | 
				
			||||||
 | 
						ExecutionOrder int            `gorm:"not null" json:"execution_order"`
 | 
				
			||||||
 | 
						Type           TaskType       `gorm:"not null" json:"type"`
 | 
				
			||||||
 | 
						Parameters     datatypes.JSON `json:"parameters"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 方案设计
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					为了实现设备和任务的多对多关系,我们将引入一个中间关联模型 `DeviceTask`。考虑到 `Task` 模型定义在 `plan.go` 中,为了保持相关模型的内聚性,我们将 `DeviceTask` 模型也定义在 `internal/infra/models/plan.go` 文件中。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 1. 在 `internal/infra/models/plan.go` 中新增 `DeviceTask` 关联模型
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`DeviceTask` 模型将包含 `DeviceID` 和 `TaskID` 作为外键,以及 GORM 的标准模型字段。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					// DeviceTask 是设备和任务之间的关联模型,表示一个设备可以执行多个任务,一个任务可以被多个设备执行。
 | 
				
			||||||
 | 
					type DeviceTask struct {
 | 
				
			||||||
 | 
						gorm.Model
 | 
				
			||||||
 | 
						DeviceID uint `gorm:"not null;index"` // 设备ID
 | 
				
			||||||
 | 
						TaskID   uint `gorm:"not null;index"` // 任务ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 可选:如果需要存储关联的额外信息,可以在这里添加字段,例如:
 | 
				
			||||||
 | 
						// Configuration datatypes.JSON `json:"configuration"` // 任务在特定设备上的配置
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TableName 自定义 GORM 使用的数据库表名
 | 
				
			||||||
 | 
					func (DeviceTask) TableName() string {
 | 
				
			||||||
 | 
						return "device_tasks"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 2. 修改 `internal/infra/models/device.go`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					在 `Device` 结构体中添加 `Tasks` 字段,通过 `gorm:"many2many:device_tasks;"` 标签声明与 `Task` 的多对多关系,并指定中间表名为 `device_tasks`。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					// Device 代表系统中的所有普通设备
 | 
				
			||||||
 | 
					type Device struct {
 | 
				
			||||||
 | 
						gorm.Model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ... 其他现有字段 ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Tasks 是与此设备关联的任务列表,通过 DeviceTask 关联表实现多对多关系
 | 
				
			||||||
 | 
						Tasks []Task `gorm:"many2many:device_tasks;" json:"tasks"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 3. 修改 `internal/infra/models/plan.go`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					在 `Task` 结构体中添加 `Devices` 字段,通过 `gorm:"many2many:device_tasks;"` 标签声明与 `Device` 的多对多关系,并指定中间表名为 `device_tasks`。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					// Task 代表计划中的一个任务,具有执行顺序
 | 
				
			||||||
 | 
					type Task struct {
 | 
				
			||||||
 | 
						// ... 其他现有字段 ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Devices 是与此任务关联的设备列表,通过 DeviceTask 关联表实现多对多关系
 | 
				
			||||||
 | 
						Devices []Device `gorm:"many2many:device_tasks;" json:"devices"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 总结
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					通过上述修改,我们将在数据库中创建一个名为 `device_tasks` 的中间表,用于存储 `Device` 和 `Task` 之间的关联关系。在 Go 代码层面,`Device` 和 `Task` 模型将能够直接通过 `Tasks` 和 `Devices` 字段进行多对多关系的查询和操作。
 | 
				
			||||||
@@ -16,4 +16,8 @@ http://git.huangwc.com/pig/pig-farm-controller/issues/50
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
1. [重构计划领域](./plan_service_refactor.md)
 | 
					1. [重构计划领域](./plan_service_refactor.md)
 | 
				
			||||||
2. [让任务可以提供自身使用设备](./add_get_device_id_configs_to_task.md)
 | 
					2. [让任务可以提供自身使用设备](./add_get_device_id_configs_to_task.md)
 | 
				
			||||||
3. [现有计划管理逻辑迁移](./plan_service_refactor_to_domain.md)
 | 
					3. [现有计划管理逻辑迁移](./plan_service_refactor_to_domain.md)
 | 
				
			||||||
 | 
					4. [增加设备任务关联表](./device_task_many_to_many_design.md)
 | 
				
			||||||
 | 
					5. [增加设备增删改查时对设备任务关联表的维护]()
 | 
				
			||||||
 | 
					6. [删除设备模板时检查]()
 | 
				
			||||||
 | 
					7. [删除区域主控时检查]()
 | 
				
			||||||
@@ -77,6 +77,9 @@ type Device struct {
 | 
				
			|||||||
	// Properties 用于存储特定类型设备的独有属性,采用JSON格式。
 | 
						// Properties 用于存储特定类型设备的独有属性,采用JSON格式。
 | 
				
			||||||
	// 建议在应用层为不同子类型的设备定义专用的属性结构体,以保证数据一致性。
 | 
						// 建议在应用层为不同子类型的设备定义专用的属性结构体,以保证数据一致性。
 | 
				
			||||||
	Properties datatypes.JSON `json:"properties"`
 | 
						Properties datatypes.JSON `json:"properties"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Tasks 是与此设备关联的任务列表,通过 DeviceTask 关联表实现多对多关系
 | 
				
			||||||
 | 
						Tasks []Task `gorm:"many2many:device_tasks;" json:"tasks"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SelfCheck 对 Device 的关键字段和属性进行业务逻辑验证。
 | 
					// SelfCheck 对 Device 的关键字段和属性进行业务逻辑验证。
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -178,6 +178,9 @@ type Task struct {
 | 
				
			|||||||
	ExecutionOrder int            `gorm:"not null" json:"execution_order"` // 在计划中的执行顺序
 | 
						ExecutionOrder int            `gorm:"not null" json:"execution_order"` // 在计划中的执行顺序
 | 
				
			||||||
	Type           TaskType       `gorm:"not null" json:"type"`            // 任务的类型,对应 task 包中的具体动作
 | 
						Type           TaskType       `gorm:"not null" json:"type"`            // 任务的类型,对应 task 包中的具体动作
 | 
				
			||||||
	Parameters     datatypes.JSON `json:"parameters"`                      // 任务特定参数的JSON (例如: 设备ID, 值)
 | 
						Parameters     datatypes.JSON `json:"parameters"`                      // 任务特定参数的JSON (例如: 设备ID, 值)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Devices 是与此任务关联的设备列表,通过 DeviceTask 关联表实现多对多关系
 | 
				
			||||||
 | 
						Devices []Device `gorm:"many2many:device_tasks;" json:"devices"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TableName 自定义 GORM 使用的数据库表名
 | 
					// TableName 自定义 GORM 使用的数据库表名
 | 
				
			||||||
@@ -197,3 +200,18 @@ func (t Task) ParseParameters(v interface{}) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return json.Unmarshal(t.Parameters, v)
 | 
						return json.Unmarshal(t.Parameters, v)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DeviceTask 是设备和任务之间的关联模型,表示一个设备可以执行多个任务,一个任务可以被多个设备执行。
 | 
				
			||||||
 | 
					type DeviceTask struct {
 | 
				
			||||||
 | 
						gorm.Model
 | 
				
			||||||
 | 
						DeviceID uint `gorm:"not null;index"` // 设备ID
 | 
				
			||||||
 | 
						TaskID   uint `gorm:"not null;index"` // 任务ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 可选:如果需要存储关联的额外信息,可以在这里添加字段,例如:
 | 
				
			||||||
 | 
						// Configuration datatypes.JSON `json:"configuration"` // 任务在特定设备上的配置
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TableName 自定义 GORM 使用的数据库表名
 | 
				
			||||||
 | 
					func (DeviceTask) TableName() string {
 | 
				
			||||||
 | 
						return "device_tasks"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user