实现 n:1 的查询

最近实现了一个查询,在查询中遇到了一些问题,在这里记录一下。

问题描述

在实现一个人员的查询功能的时候,有两个查询条件:人员资质有效期至,人员和人员资质的关系是1:n,有效期至是人员资质的一个字段。在实现这个查寻的时候,而在后台通过n的一方来查询1的一方是很不好实现的。

解决办法

这个问题最后考虑在前台使用过滤器来实现,首先将满足其他查询条件的查询出来,然后将没有相应人员资质的人员过滤掉,这样就实现了。

解决过程

1.引入过滤器

首先我们知道,过滤器是通过管道符来使用的:

1
objects | filter

然后就是过滤器参数的问题,在管道符前面的objects就是第一个参数,过滤器至少有一个参数。现在有人员资质和有效期至,这两个是过滤的条件,必然也要作为参数。那么过滤器是如何传参的呢?

1
objects | filter: param

在过滤器后面写一个冒号:,然后冒号后面的就是参数。那两个参数呢?

1
objects | filter: param1: param2

连续使用冒号:就可以传多个参数了。好了,下面来解决我们的问题。

1
<tbody ng-repeat="person in persons | yunzhiPersonnel: params.qualifierCertificateType: params.validityDate">

然后实现过滤器的基本思想就是首先遍历人员,再遍历人员中的人员资质,当人员资质和查询的人员资质相同的时候,就将这个人员放到返回列表中,最后统一返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
...
self.getQualifierWithQualifierCertificate = function(personnels, qualifierCertificateType, validityDate) {
var persons = []; // 初始化符合条件的人员
// 遍历人员
angular.forEach(personnels, function(personnel) {
var qualifierCertificates = personnel.qualifier.qualifierCertificate; // 获取人员资质
// 如果输入了两个查询条件
if (qualifierCertificateType.id && validityDate) {
// 遍历人员资质
angular.forEach(qualifierCertificates, function(qualifierCertificates) {
// 当资格证类别与查询的资格证类别相同,并且有效期至也相同时,将人员放入返回人员数组中
if (qualifierCertificates.qualifierCertificateType.name === qualifierCertificateType.name && qualifierCertificates.validityDate === validityDate) {
persons.push(personnel);
}
});
// 如果输入资格证类别
} else if (qualifierCertificateType.id) {
// 遍历人员资质
angular.forEach(qualifierCertificates, function(qualifierCertificates) {
// 资格证类别与查询的资格证类别相同
if (qualifierCertificates.qualifierCertificateType.name === qualifierCertificateType.name) {
persons.push(personnel);
}
});
// 输入有效期至
} else {
// 遍历人员资质
angular.forEach(qualifierCertificates, function(qualifierCertificates) {
// 有效期至与查询的有效期至相同
if (qualifierCertificates.validityDate === validityDate) {
persons.push(personnel);
}
});
}
});
return persons;
};
...

2.过滤器及时生效

上面我在设置参数的时候,直接将查询的参数当做过滤参数,所以一旦输入了查询条件,就会直接过滤。而我们要的效果是,在用户点击查询后在显示过滤后的数据。

首先想到的是,在给这个过滤器一个参数:是否点击了查询。只有当用户点击了查询,这个参数为true,然后执行过滤,没有点击,这个参数为false,不执行过滤。

1
<tbody ng-repeat="person in persons | yunzhiPersonnel: params.qualifierCertificateType: params.validityDate:touched">
1
2
3
4
5
6
7
...
if(touched) {
return self.getQualifierWithQualifierCertificate(personnels, qualifierCertificateType, validityDate);
} else {
return personnels;
}
...

但是这种解决方法并不好。一个问题是,这种解决方法会带来一些其他的问题,比如说先查询了一次,再查询一次就又会出现上面直接出结果的问题;另一个问题,也是主要的问题,这种方法不符合规范,过滤器的职能就是过滤,不应该在过滤器中判断什么时候开始过滤,什么时候不过滤,而应该是我在需要过滤的时候,再给他过滤条件,不需要过滤的时候,就不给他过滤条件。

所以,在控制器中重新定义一个函数,用来获取过滤条件,这个方法在点击查询的时候调用。

1
<tbody ng-repeat="person in persons | yunzhiPersonnel: filterParams.qualifierCertificateType: filterParams.validityDate">
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 获取过滤参数
self.getFilterParams = function() {
return {
qualifierCertificateType: $scope.params.qualifierCertificateType, // 资格证类别
validityDate: $scope.params.validityDate, // 有效期至
// 这里还可以添加其他过滤条件
};
};
// 提交查询
self.submit = function() {
...
$scope.filterParams = self.getFilterParams(); // 设置过滤条件
...
};

总结

我们这种mvc的开发思想,在实现每一部分的时候,都要尽可能的使每一部分都只做自己的功能,这样不仅能增加代码的可读性,同时也增加了可维护性,在后面进行改写的时候也会减小压力。

坚持原创技术分享,您的支持将鼓励我继续创作!