Repository 层的代码如何封装才比较合适?

2021-05-28 12:09:22 +08:00
 waibunleung

有两个 case,分别是不同人封装的,下面是伪代码:

case1:

// 根据用户昵称获取用户信息
function findUserByName(name){
    // 获取数据库链接
    db = _get_db()
    if (not db){
    	return error
    }

	// orm 查询
    user, err = db.where('name', name).get(table_name)
    if (err) {
        LOG("查找姓名失败", err)
        return error
    }

    return user
}

// 根据用户 ID 获取用户信息
function findUserById(userid){
    // 获取数据库链接
    db = _get_db()
    if (not db){
    	return error
    }

	// orm 查询
    user, err = db.where('id', userid).get(table_name)
    if (err) {
        LOG("查找用户 id 失败", err)
        return error
    }

    return user
}

// service 层调用
user1 = userRepo.findUserByName('拜拜你条尾')
user2 = userRepo.findUserById(12)
code ...

case2:

// 简单封装了查询函数?
function query(where_array, limit){
    // 获取数据库链接
    db = _get_db()
    if (not db){
    	return error
    }
	
    // orm 查询
    user, err = db.where(where_array).limit(limit).get(table_name)
    if (err) {
        LOG("查找用户失败", err)
        return error
    }

    return user
}

// service 层调用
user1 = userRepo.query({name = '拜拜你条尾'}, 1)
user2 = userRepo.query({id = 12}, 1)
code ...

case2 这种封装有点迷的感觉,不能 cover 大部分的情况(where in/ or 之类),那这样的封装的意义何在?倒不如像第一种一样,不同的查询条件就封装一个方法,见名知意,不会给人带来疑惑?

不知道各位怎么看...

另外像请教下大家在这一层是怎么封装代码的?

3355 次点击
所在节点    程序员
32 条回复
ikesnowy
2021-05-28 18:32:49 +08:00
可以参考 CQRS 的操作。

由于查询不存在副作用,因此可以不用拘泥于 domain 和 repository,直接从 domain 的上一层调用 orm 查询就可以了,domain 只提供一个实体的数据结构(当然你也可以另外弄 DTO,直接去掉对 domain 的依赖,怎么方便怎么来)

于是 repository 就只需要一个 `getEntityById()` 的方法,由上层(调用方,或者 application service )先通过复杂查询搞到 Id,在执行写命令的时候提供这个 Id 就可以。
forgottencoast
2021-05-28 23:09:28 +08:00
简单,case 1 调用 case 2.
可以考虑把 case 2 作为高级接口开放出去。
mcfog
2021-05-29 01:08:25 +08:00
@waibunleung 是可以,不是必须或推荐
我说 2 是 helper 其实是说 2 不可能把自己叫 repo,理由其实和其他人一样的,封装层次的问题

至于 1 调 2 合理的可能性,比如 ORM 不够甜增加一些甜度,比如 where 是焦点问题(取决于项目情况可能有注入、扫表性能等等等各种痛点),通过收口( repo 不写 where 了)来解决某个问题

你也说了是跨语言聊,所以其实也说不了不同语言的常见 ORM 问题有啥,所以其实说不了 2 的存在合不合理,但 2 当作 repo 层的可能性是不存在的
waibunleung
2021-05-29 15:02:33 +08:00
@forgottencoast 高级接口?有 orm 了这种高级接口就显得,你想用又不想用的样子....
waibunleung
2021-05-29 15:05:53 +08:00
@mcfog 大概了解了
waibunleung
2021-05-29 23:00:30 +08:00
@mcfog 但是我又有另一个疑问是,多条件搜索的时候,case1 这种写法应该怎么写?比如用户管理后台,可以根据用户 id,姓名,状态,类型等进行搜索那就要写个 getUserList(id, name, status, type, page, page_size){ code... } 这样的函数?
waibunleung
2021-05-29 23:02:09 +08:00
但是我又有另一个疑问是,多条件搜索的时候,case1 这种写法应该怎么写?比如用户管理后台,可以根据用户 id,姓名,状态,类型等进行搜索那就要写个 getUserList(id, name, status, type, page, page_size){ code... } 这样的函数?
@devld
@BeautifulSoap
@xiaoyiqingz
@simonlu9
waibunleung
2021-05-29 23:15:52 +08:00
其实是再想问下动态查询的时候,repository 层的代码要怎么写比较好
BeautifulSoap
2021-05-29 23:20:07 +08:00
@waibunleung

搜索有一点儿复杂的时候,可以定义个搜索条件的 struct 或类,根据需要的搜索的内容填上信息。这个 struct/类是和具体表结构无关的。或者写个简单的 query builder,这个 qury builder 依旧是和具体数据结构无关,然后把 builder 交给 repository 进行具体的搜索

如果是非常复杂的搜索的话,应该使用 CQRS
waibunleung
2021-05-30 02:40:41 +08:00
@BeautifulSoap 构建 query builder 是在 service 层构建吧?那构建完了我在 service 层直接 execute 这个 builder 不就可以了吗,还要扔到 repository 层?如果扔到 repository 层,那 repository 层只是简单执行并返回结果就好了,感觉有点怪怪的....

我感觉是不是应该是
```
// UserController 层
function List(req request) {
id = req.id
status = req.status
name = req.name
type = req.type
page = req.page
pageSize = req.page_size

res = userService.getUserList(id, status, name, type, page, pageSize)
return res
}

// UserService 层
function getUserList(id, status, name, type, page, pageSize) {

res = userRepository.getUserList(id, status, name, type, page, pageSize)
return res
}


// repository 层
function getUserList(id, status, name, type, page, pageSize) {
db = getDb() // orm 对象
if (id > 0){
db.where('id', id)
}
if (status > 0){
db.where('status', status)
}
if (name != ''){
db.like('name', '%' + name + '%')
}
.......
return db.orderBy(id, 'desc).limit(page, page_size).get()
}

```
BeautifulSoap
2021-05-30 11:58:00 +08:00
@waibunleung 你给 builder 定义个接口,然后 builder 的实现放到 infrastructure 里,上层调用 builder 的接口也没问题啊。我上面说把 builder 扔给 repository 是针对定义个简单搜索条件的 struct/类来说的,看做 struct/类的简单升级版。如果真想写个复杂点的 query builder,直接在 infrastructure 实现 query builder 会更好。如果还要复杂了,那考虑使用 CQRS
chaleaochexist
272 天前
大佬我遇到了和你一样的问题, 大佬最近有什么新体会吗?
欢迎分享.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/779785

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX