如何处理淘汰视图模型中的多对多关系

时间:2014-03-23 10:28:23

标签: knockout.js

我的架构中有两个表服务员工之间的多对多关系(一个服务可以由多个员工执行,一个员工可以执行多个服务的) 。我使用 ServiceEmployee 联结表来创建此关系。

我在客户端使用淘汰赛。淘汰视图模型是通过服务器端viewmodel的knockout.mapping插件创建的。在服务器端,我有3个viewmodel:

  1. EmployeeModel(包含ServiceEmployeeModel 列表)

  2. ServiceModel(包含ServiceEmployeeModel 列表)

  3. ServiceEmployeeModel(包含ServiceId,EmployeeId)[不能包括Employee和 服务对象以避免客户端的自引用循环]

  4. 现在在客户端我有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;
                    }
                }
            });
        }
    }
    

    我正在使用的方法正在运行,但我觉得应该有一些其他更好的方法来处理这种情况。因为在这种方法中如果我们将服务分配给员工或员工服务,那么我们必须手动更新Employees和Services数组,我觉得应该有更好的方法,以便淘汰赛将为我更新这些数组。

    计算的可观察量可能是解决方案,但我无法得到它。有人可以帮我解决这个问题吗?

1 个答案:

答案 0 :(得分:0)

解决方案A:

您可能想尝试使用breeze: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插件的ignore属性,例如尝试此操作:

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