如何验证Ember Data中hasMany关联与另一hasMany关联的匹配性
嘿,我来帮你搞定这个Ember Data的关联校验问题!先把你的模型结构明确出来(方便咱们后续参考),然后给你几种实用的实现方式~
实现Item与Restriction的类型关联校验
你的现有模型结构
Type 模型
// app/models/type.js import Model from 'ember-data/model'; export default Model.extend({});
Restriction 模型
// app/models/restriction.js import Model from 'ember-data/model'; import { hasMany } from 'ember-data/relationships'; export default Model.extend({ allowedTypes: hasMany("type") });
Item 模型(待添加校验逻辑)
// app/models/item.js import Model from 'ember-data/model'; import { hasMany } from 'ember-data/relationships'; export default Model.extend({ types: hasMany("type") });
方式一:自定义校验方法(按需调用)
这种方式适合在需要校验的时机主动调用,比如表单提交前、数据保存前。要注意的是,Ember Data的hasMany返回的是PromiseArray,必须处理异步加载的情况:
// app/models/item.js import Model from 'ember-data/model'; import { hasMany } from 'ember-data/relationships'; import { Promise } from 'rsvp'; export default Model.extend({ types: hasMany("type"), // 校验当前item的types是否符合指定restriction的规则 async isTypesValidForRestriction(restriction) { // 先等关联数据加载完成 const [itemTypes, allowedTypes] = await Promise.all([ this.get('types').toArray(), restriction.get('allowedTypes').toArray() ]); // 把允许的type id提取成数组,方便快速判断 const allowedTypeIds = allowedTypes.map(type => type.get('id')); // 检查每个item的type是否都在允许列表里 return itemTypes.every(type => allowedTypeIds.includes(type.get('id'))); } });
调用示例(比如在组件或路由里):
// 假设你已经拿到了item和对应的restriction实例 const isValid = await item.isTypesValidForRestriction(restriction); if (isValid) { // 校验通过,执行保存或其他操作 await item.save(); } else { // 校验失败,给用户提示 alert('当前选择的类型不符合限制规则哦!'); }
方式二:用Ember验证库做系统校验
如果你的场景是表单提交,需要更规范的错误提示和状态管理,可以用ember-cp-validations这个常用的验证库:
首先安装依赖:
ember install ember-cp-validations
然后修改Item模型(这里假设Item和Restriction是通过belongsTo关联的,如果不是,你可以手动传入Restriction实例):
// app/models/item.js import Model from 'ember-data/model'; import { hasMany, belongsTo } from 'ember-data/relationships'; import { validator, buildValidations } from 'ember-cp-validations'; const Validations = buildValidations({ types: validator('custom', { validate(value, options, model) { const restriction = model.get('restriction'); if (!restriction) return true; // 没有限制的话默认通过 return Promise.all([ value.toArray(), restriction.get('allowedTypes').toArray() ]).then(([itemTypes, allowedTypes]) => { const allowedIds = allowedTypes.map(t => t.get('id')); const invalidTypes = itemTypes.filter(t => !allowedIds.includes(t.get('id'))); if (invalidTypes.length > 0) { return `以下类型不符合限制:${invalidTypes.map(t => t.get('id')).join(', ')}`; } return true; }); } }) }); export default Model.extend(Validations, { types: hasMany("type"), restriction: belongsTo("restriction") // 假设item关联了对应的restriction });
之后就能在模板里直接用验证状态了:
{{#if item.validations.isInvalid}} <div class="error-message"> {{item.validations.errors.types.firstObject.message}} </div> {{/if}}
方式三:保存前自动校验
如果你想让Item在保存时自动触发校验,不通过就阻止保存,可以重写模型的save方法:
// app/models/item.js import Model from 'ember-data/model'; import { hasMany, belongsTo } from 'ember-data/relationships'; import { Promise } from 'rsvp'; export default Model.extend({ types: hasMany("type"), restriction: belongsTo("restriction"), async save(options) { // 先做校验 const isValid = await this.isTypesValidForRestriction(this.get('restriction')); if (!isValid) { throw new Error('Item的类型不符合Restriction的限制规则'); } // 校验通过才调用原生save方法 return this._super(options); }, // 复用方式一的校验方法 async isTypesValidForRestriction(restriction) { const [itemTypes, allowedTypes] = await Promise.all([ this.get('types').toArray(), restriction.get('allowedTypes').toArray() ]); const allowedTypeIds = allowedTypes.map(type => type.get('id')); return itemTypes.every(type => allowedTypeIds.includes(type.get('id'))); } });
调用时可以捕获错误做处理:
try { await item.save(); } catch (error) { console.error(error.message); // 给用户显示友好的错误提示 }
注意事项
- 异步关联要等待加载:因为
hasMany默认是异步的,一定要用await或.then()等数据加载完成再做比较,不然会拿到空数组导致校验出错。 - 关联关系要明确:如果Item和Restriction不是直接关联的,记得在调用校验方法时手动传入Restriction实例,或者通过其他逻辑获取到对应的Restriction。
内容的提问来源于stack exchange,提问作者MT0
相关产品推荐
相关产品推荐

