如何处理淘汰视图模型中的多对多关系
Posted
技术标签:
【中文标题】如何处理淘汰视图模型中的多对多关系【英文标题】:How to handle many to many relationship in knockout viewmodels 【发布时间】:2014-04-30 15:25:36 【问题描述】:我的架构中有 2 个表 Service 和 Employee 之间的多对多关系(一个服务可以由多个员工执行,一个员工可以执行多个服务) .我使用 ServiceEmployee 联结表来创建这种关系。
我在客户端使用淘汰赛。淘汰视图模型是通过来自服务器端视图模型的 knockout.mapping 插件创建的。在服务器端,我有 3 个视图模型,它们是:
EmployeeModel(包含 ServiceEmployeeModel 列表)
ServiceModel(包含 ServiceEmployeeModel 列表)
ServiceEmployeeModel(包含 ServiceId、EmployeeId)[不能包括 Employee 和 服务对象以避免客户端的自引用循环]
现在在客户端我有 3 个模块:
员工模块
function Employee(data)
var self = this;
ko.mapping.fromJS(data,
"Services":
create: function (options)
return new serviceEmployee(options.data, options.parent);
, self);
....
服务模块
function Service(data)
var self = this;
ko.mapping.fromJS(data,
"Employees":
create: function (options)
return new serviceEmployee(options.data, options.parent);
, self);
....
ServiceEmployee 模块
function (data, parent)
var self = this;
ko.mapping.fromJS(data, self);
//If parent object has property EmployeeId it means the parent object is Employee
//object and we will add only related Service (not Employee) in order
//to avoid self reference loop.
if (parent.EmployeeId)
self.Service = ko.computed(function ()
if (self.ServiceId())
var services = require("modules/tenant").services();
if (services)
var assignedService;
ko.utils.arrayFirst(services(), function (service)
if (service.ServiceId() === self.ServiceId())
assignedService = service;
return true;
);
return assignedService;
);
//If parent object has property ServiceId it means the parent object is Service
//object and we will add only related Employee (not Service) in order
//to avoid self reference loop.
if (parent.ServiceId)
self.Employee = ko.computed(function ()
if (self.EmployeeId())
var staff = require("modules/tenant").staff();
if (staff)
var assignedEmployee;
ko.utils.arrayFirst(staff(), function (employee)
if (employee.EmployeeId() === self.EmployeeId())
assignedEmployee = employee;
return true;
);
return assignedEmployee;
);
我使用的方法很有效,但我觉得应该有其他更好的方法来处理这种情况。因为在这种方法中如果我们将服务分配给员工或员工服务,那么我们必须手动更新员工和服务数组,我觉得应该有一些更好的方法,以便淘汰赛会为我更新这些数组。
Computed observable 可能是解决方案,但我不知道如何解决。谁能帮我解决这个问题?
【问题讨论】:
你说的自引用循环,是指你运行toJSON的时候吗? 【参考方案1】:解决方案 A:
您可能想尝试微风:http://www.breezejs.com/ 他们不直接支持多对多关系,但是如果您像这样公开 navigaiton 对象:
Service.Employees // Array of ServiceEmployee
ServiceEmployee.Employee // Employee
ServiceEmployee.Service // Service
Employee.Services // Array of ServiceEmplyee
Breeze 提供了自动跟踪哪些员工和服务相关的机制,允许您执行以下操作:
var myEmployeesServices = ko.computed(function ()
return myEmployee.Services().map(function (a)
return a.Service;
;
); // an always up to date array of services related to a specific employee
var newService = entityManager.createEntity("Service", )
//entityManager is a class defined by breeze
//createEntity is a function provided to create new breeze managed objects
var newServiceLink = entityManager.createEntity("ServiceEmployee",
EmployeeId: myEmployee.Id,
ServiceId: newService.Id
); // creates a new ServiceEmployee object linking myEmployee and newService
// myEmployeeServices now also contains newService
如果你想使用微风,你必须阅读其他微风功能,例如加载和保存数据等。
解决方案 B:
您可能想查看 ko.mapping 插件的忽略属性,例如:
function Employee(data)
var self = this;
ko.mapping.fromJS(data,
"Services":
create: function (options)
return new serviceEmployee(options.data, options.parent);
, self);
self.ServiceObjects = ko.computed(function ()
var staff = require("modules/tenant").services();
return staff().filter(function (a)
return self.Services.filter(function (b)
return b.ServiceId() == a.ServiceId();
).length;
)
);
....
function serviceEmployee(data, parent)
this.EmployeeId = parent.EmployeeId || data.EmployeeId;
this.ServiceId = parent.ServiceId || data.ServiceId;
如果我正确编写了映射部分(不确定是否正确,请在此处查看更多详细信息http://knockoutjs.com/documentation/plugins-mapping.html),那么当您取消映射员工模型时,映射插件应该忽略您计算的 ServiceObjects
您还可以通过在 Services 数组中添加和删除对象以响应 ServiceObjects 数组中的更改来添加写入函数以添加到您的数组中。
解决方案 C:
看看这个其他解决方案:Knockout JS ObservableArray with many-to-many relationships
【讨论】:
以上是关于如何处理淘汰视图模型中的多对多关系的主要内容,如果未能解决你的问题,请参考以下文章