breeze:保存时的多对多问题

breeze:保存时的多对多问题,breeze,Breeze,我已经为微风应用程序中的多对多关联挣扎了一段时间。我在客户端和服务器端都有问题,但现在,我只公开我的客户端问题。我不知道我提出的方法是否正确,我真的很想从breeze团队得到以下方面的反馈: 我的商业模式: public class Request { public virtual IList<RequestContact> RequestContacts { get; set; } } public class RequestContact { public

我已经为微风应用程序中的多对多关联挣扎了一段时间。我在客户端和服务器端都有问题,但现在,我只公开我的客户端问题。我不知道我提出的方法是否正确,我真的很想从breeze团队得到以下方面的反馈:

我的商业模式:

public class Request 
{
    public virtual IList<RequestContact> RequestContacts { get; set; }
}

public class RequestContact 
{
    public virtual Contact Contact { get; set; }
    public virtual Guid ContactId { get; set; }
    public virtual Request Request { get; set; }
    public virtual Guid RequestId { get; set; }
}


public class Contact 
{
    public virtual Client Client { get; set; }
    public virtual Guid? ClientId { get; set; }
    public virtual string Username { get; set; }
}
视图绑定到控制器中定义的联系人数组:

<select ng-multiple="true" multiple class="multiselect" data-placeholder="Select Contacts" ng-change="updateBreezeContacts()" ng-model="request.contacts" ng-options="c as c.username for c in contacts | filter:{clientId: request.client.id} track by c.id"></select>
//the collection to which the multiselect is bound: 

$scope.contacts = dataService.lookups.contacts;
无论何时在multiselect中选择或取消选择项目,都会调用此方法:

$scope.updateBreezeContacts = function () {
  //wipe out all the RequestContact entities
  $scope.request.requestContacts.forEach(function (req) {
    req.entityAspect.setDeleted();
  });

  //populate the RequestContact based on selected contacts 
  for (var i = 0; i < $scope.request.contacts.length; i++) {
     var requestContact = dataService.createRequestContact($scope.request,    $scope.request.contacts[i]);
     $scope.request.requestContacts.push(requestContact);
  }
用例场景:


  • 该请求有一个选定的联系人
  • 用户取消选择联系人,然后从列表中选择另一个联系人
  • 然后她决定重新选择以前未选择的一个。我们现在有两个选定的联系人
  • 用户点击save按钮,调用saveChanges。Breeze向服务器发送3个实体:第一个联系人的状态为“已删除”,第二个联系人的状态为“已添加”,最后一个联系人的状态为“已添加”

这是与多对多协会合作时应该做的吗


实际上,我收到了一个服务器错误(“not null属性引用了null或暂时值Business.Entities.RequestContact.Request”),但在我得出任何结论之前,我想知道我在客户端所做的是否正确。

Breeze.js客户端此时不支持“多对多”关系。您必须将连接/映射表作为一个实体公开。关于同一主题还有其他几篇文章

我们确实计划在未来增加许多支持。抱歉,还没有日期…

服务器端 首先要处理服务器端建模问题。我在对你的问题的评论中注意到没有PKs。我建议你在和客户打交道之前先开始工作

客户端 我对这种情况有很长的经验。对我来说,典型的情况是用户可以拥有任意数量的角色,并且他/她拥有的角色在UserRoles表中

典型的用户界面:

  • 选择并呈现一个用户
  • 使用前面的复选框显示该用户所有可能角色的列表
  • 如果用户具有该角色,则选中该复选框;如果他/她没有,则未选中
哦 我多次看到人们将所有可能的角色列表绑定到
UserRole
实体列表。这很少奏效

很多时候,我看到人们在用户单击复选框时创建和销毁
UserRole
实体。这很少奏效

我经常看到在缓存中添加和删除
UserRole
实体。这通常是致命的,因为客户端无法跟踪
UserRole
实体此时是否与数据库中的记录对应

如果我正确地阅读了您的代码,您就犯了所有这些错误

改为项目视图模型 当我将此用户的角色表示为“Item ViewModel”实例的列表时,我取得了更大的成功,并将实体操作推迟到保存用户选择的时间

为了便于讨论,让我们将此对象称为aUserRoleVm。它可以在JavaScript中定义如下

{
    role,
    isSelected,
    userRole
}
构建屏幕时

  • 填充
    UserRoleVm
    实例列表,每个
    角色一个

  • 使用适当的
    角色
    实体设置每个vm的
    角色
    属性

  • 将视图绑定到
    vm.role.name

  • 当且仅当相关用户的
    userRole
    实体已经存在时,才使用相关用户的
    userRole
    实体设置每个vm的
    userRole
    属性

  • 如果虚拟机具有
    userRole
    且未删除
    vm.userRole.entityAspect.entityState,则设置虚拟机的
    isSelected=true

  • 将虚拟机的
    isSelected
    绑定到复选框

现在用户可以随意选择和取消选择

在此过程中,我不会创建/删除/修改任何
UserRole
实体。我等待UI信号保存(不管该信号是什么)

在保存准备过程中,我迭代了
UserRoleVm
实例列表

  • 如果未选中并且没有vm.userRole,则不执行任何操作

  • 如果未选中并具有
    vm.userRole
    ,则
    vm.userRole.entityAspect.setDeleted()
    。如果分离了
    vm.userRole.entityAspect.entityState
    (意味着它以前处于添加状态),则将
    vm.userRole
    =null

  • 如果选中并且没有
    vm.userRole
    ,则创建一个新的
    userRole
    ,并将其分配给
    vm.userRole

  • 如果选中并具有
    vm.userRole
    ,则如果
    vm.userRole.entityAspect.entityState

    • 不变,什么也不做
    • 已修改(为什么?如何?),通过调用
      vm.userRole.entityAspect.rejectChanges()
    • 已删除(必须是“未选中”但仍未保存的预先存在的
      UserRole
      ;这是如何发生的?),通过调用
      vm.UserRole.entityAspect.rejectChanges()进行还原
现在调用
manager.saveChanges()

  • 如果保存成功,则一切正常

  • 如果失败,最干净的方法是调用
    manager.rejectChanges()
    。这将清除组(并放弃用户自上次保存以来所做的任何更改)

  • 无论哪种方式,都要像我们开始时那样从头开始重建列表

理想情况下,在异步保存成功或失败返回之前,不允许用户对用户角色进行更多更改

我相信你会比这更聪明。但这种方法是稳健的

变化 不要打扰w
manager.createEntity('RequestContact', { request: myRequest, contact: myContact});
{
    role,
    isSelected,
    userRole
}
<li ng-repeat="role in vm.userRoles"> ... <input type="checkbox" ng-model="role.isSelected" ng-click="vm.userRoleClicked(role)"</input> ... </li>