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

use*_*381 8 knockout.js

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

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

  1. EmployeeModel(包含ServiceEmployeeModel列表)

  2. ServiceModel(包含ServiceEmployeeModel列表)

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

现在在客户端我有3个模块:

员工模块

function Employee(data)
{
    var self = this;

    ko.mapping.fromJS(data, {
        "Services": {
            create: function (options) {
                return new serviceEmployee(options.data, options.parent);
            }
        }
    }, self);

    ....    
}
Run Code Online (Sandbox Code Playgroud)

服务模块

function Service(data)
{
    var self = this;

    ko.mapping.fromJS(data, {
        "Employees": {
            create: function (options) {
                return new serviceEmployee(options.data, options.parent);
            }
        }
    }, self);

    ....    
}
Run Code Online (Sandbox Code Playgroud)

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;
                }
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在使用的方法是工作,但我觉得应该有一些其他更好的方法来处理这种情况.因为在这种方法中,如果我们将服务分配给Employee OR Employees to Service,那么我们必须手动更新Employees和Services数组,我觉得应该有更好的方法,以便knockout将为我更新这些数组.

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

cwo*_*man 0

方案一:

您可能想尝试微风:http://www.breezejs.com/他们不直接支持多对多关系,但如果您像这样公开 navigaiton 对象:

Service.Employees // Array of ServiceEmployee
ServiceEmployee.Employee // Employee
ServiceEmployee.Service // Service
Employee.Services // Array of ServiceEmplyee
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

如果您想使用微风,您必须阅读其他微风功能,例如加载和保存数据等。

方案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;
}
Run Code Online (Sandbox Code Playgroud)

如果我正确地编写了映射部分(不确定我是否正确,请在此处查看更多详细信息http://knockoutjs.com/documentation/plugins-mapping.html),那么当您取消映射员工模型时,映射插件应该忽略您计算的 ServiceObjects

您还可以添加一个写入函数,通过在 Services 数组中添加和删除对象来添加到数组中,以响应 ServiceObjects 数组中的更改。

方案C:

看看另一个解决方案:Knockout JS ObservableArray with multiple-to-many transactions