英文:
Implementing SOLID Design in Go application
问题
最好的方法是将模型(用户)和数据库建模,避免出现循环依赖。你可以将数据库存储和模型分开处理,以解决这个问题。在数据库存储中,你可以定义创建表的方法,并在其中进行模型的迁移操作。在模型中,你可以定义验证方法,但不需要导入数据库存储。这样可以避免循环依赖的问题。
你可以将数据库存储和模型放在不同的包中,然后在需要的时候进行导入。另外,你可以将迁移操作作为启动过程的一部分,以确保在应用程序启动时进行数据库表的创建和迁移。
我的解决方案是将数据库指针解耦为一个单独的包,并将迁移操作作为引导过程的一部分。然而,我仍然将验证方法保留在模型包中。这样做可以保持结构的清晰性和关注点的分离。
希望对你有所帮助!
英文:
What's the best way to model a model (user) and a database without running into circular dependencies?
I have a Go application that I'm trying to set up. The structure of imports is confusing because it doesn't cleanly appear to divide along separation of concerns. I would like to have a database store that requires access to the names of models to migrate them. It seems odd to have models migrate themselves and that seems like an unrelated concern to the models. At the same time, I would like to have validations per model that require the importing of the database store. It seems even more odd to have the store validate individual models. This creates a circular dependency however.
structure:
models
- user.go
config
- store.go
store.go
...
// CreateDb - creates table
func (i *Store) CreateDb() {
...
i.DB.AutoMigrate(&models.User{})
...
}
...
user.go
package models
type User struct {
Email string
}
func (u *User) ValidateUser() (err []error) {
messages := make([]error, 0)
// Uniqueness Validations
email := ""
email = config.Database.DB.Where("email LIKE ?", u.Email).First(&User)
if email != "" {
messages = append(messages, errors.New("Email has to be unique"))
}
return messages
}
I've tried putting them into a third package but that fails because they both require the same dependency - store. I've also tried putting them all into the same package which I suppose works but that seems to breakdown all structure and sep of concerns.
Advice?
My solution
I ended up decoupling the database pointer into a separate package and then made the migrations a part of a bootstrap process. I kept validations in line with the models package however.
答案1
得分: 1
我不是Go语言专家,但由于这是一个设计问题,所以并不重要。禁止重复电子邮件是一个业务需求。此外,根据业务需求,在进行验证之前/之后可能还有其他需要完成的工作,但在访问数据库存储之前。
我会将验证放在另一个包中,作为业务逻辑层,并引用模型和存储包。我会保持模型的清晰,就像在C#、Java中使用的POCO、POJO一样。不知道在Go语言环境中该如何称呼它们。POGO已经为Groovy保留了:)
请参考下面的伪代码:
// 业务逻辑
function AddUser(email) {
User user;
// 验证
user = store.GetUserByEmail(email);
if (user) {
// 抛出异常
}
else {
user = new User { Email = email }; // 初始化用户实例以进行存储
store.InsertUser(user);
}
}
这只是我谈论的基础部分。您可以定义业务包使用的接口,用于与存储进行通信,然后进行依赖注入等等。
英文:
I am not a Go guy but since it's a design question, it doesn't matter. Disallowing duplicate emails is a business requirement. Moreover as per business requirements there can be other stuff that you need to do before/after validations but before hitting database store.
I would put validations in another package which will act as a business logic layer and references model and store packages. I will keep models clean like we have POCO, POJO in C#, Java respectively. Don't know what to call them in Go context. POGO is reserved for Groovy :).
See the pseudo code below:
// business
function AddUser(email) {
User user;
// validate
user = store.GetUserByEmail(email);
if (user) {
// shout
}
else {
user = new User { Email = email }; // basically initialize user instance to store
store.InsertUser(user);
}
}
That's just basic I talked about. You could define interfaces that your business package uses to talk to store, followed by dependency injection and what not.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论