这是很多问题,每个问题都是一个大话题。我能做的最好的就是为你指明一些方向。
在开始之前,让我解释一下为什么您没有看到设置“ModifiedBy、ModifiedTime、CreatedBy 等属性”的效果。 EFContextProvider 不会更新修改后的实体 的所有属性,而只会更新EntityInfo.OriginalValuesMap 中提到的那些属性,这是一个包含属性名称和仅已更改属性的原始值的字典。如果要保存仅在服务器上设置的属性,只需将其添加到原始值映射中即可:
var map = EntityInfo.OriginalValuesMap;
map["ModifiedBy"]=null; // the original value does not matter
map["ModifiedTime"]=null;
现在 Breeze 也知道保存这些属性,并且它们的新值将返回给客户端。
让我们回到大局。
Breeze 首先是一个客户端 JavaScript 库。只要您的服务器使用 HTTP 和 JSON,您几乎可以在服务器端做任何您想做的事情并让 Breeze 高兴。
无论您喜欢哪种技术,编写一个能够提供您需要的所有功能的服务器都不是一件容易的事。 Breeze 的作者提供了一些开箱即用的 .NET 组件,让您的工作更轻松,尤其是当您选择 Web API、EF 和 SQL Server 堆栈时。
我们的 .NET 演示通常将所有内容都放入一个 Web 应用程序中。这不是我们在实践中滚动的方式。在现实生活中,我们永远不会在我们的 Web API 控制器中实例化 Breeze EFContextProvider。该控制器(或多个控制器)将委托给负责业务逻辑和数据访问的外部类,可能是存储库或工作单元 (UoW) 类。
带有 Breeze .NET 组件的存储库模式
我们倾向于为模型(通常是 POCO)、数据访问 (ORM) 和 Web(Web API 加上客户端资产)项目创建单独的项目。您会在 DocCode Sample 和 John Papa 的 Code Camper 示例中看到这种分离,这是他的 PluralsSight 课程“Building Apps with Angular and Breeze”的伴侣。
这些示例还演示了存储库模式的实现,它将多个存储库和 UoW 的职责混合在一个类中。这对于这些样本中的小型模型是有意义的。没有什么可以阻止您将存储库重构为单独的类。
我们将存储库类与 EF 数据访问材料保存在同一个项目中,因为我们认为为这个小目的创建另一个项目没有特别的价值。如果你下定决心,重构成一个单独的项目并不难。
Breeze 和 Code Camper 示例都专注于 Breeze 客户端开发。它们在服务器端逻辑上很薄。也就是说,您将在 DocCode 示例中的“NorthwindRepository.cs”和“NorthwindEntitySaveGuard.cs”文件的BeforeSaveEntities 扩展点中找到应用自定义业务逻辑的宝贵线索。您将看到如何将保存限制为某些类型以及基于发出请求的用户的这些类型的某些记录。
如果您尝试通过单个端点传递所有保存更改请求,则逻辑可能会不堪重负。你不必那样做。您可以有多个保存端点,每个端点都专用于特定的业务操作,仅限于以高度特定的方式插入/更新/删除几种类型的实体。你可以随心所欲。请参阅"Saving Entities" topic 中的“命名保存”。
随心所欲
现在有无数种方法可以实现存储库和 UoW 模式。
您可以按照您引用的帖子所述的方式进行。在这种情况下,您不需要 Breeze .NET 组件。将您的 Web API 查询方法(IQueryable 或不)连接到返回 IQueryable(或只是对象)的存储库方法非常简单。 Web API 不必知道您在幕后是否有 Breeze EFContextProvider 或完全不同的东西。
处理 Breeze 客户端的 SaveChanges 请求有点棘手。也许您可以从ContextProvider 或EFContextProvider 派生;也许不吧。 Study the "ContextProvider.cs" documentation 和 source code,尤其是 SaveChanges 方法,您将看到您需要做些什么才能让 Breeze 客户端满意并与之交互,但是您希望使用 UoW 处理更改集保存。
假设您在客户端没有更改任何内容(这是一个假设,而不是给定的......您可以根据需要更改保存协议),您的 SaveChanges 只需要做两个事情:
- 解释来自客户端的“saveBundle”。
- 返回与
SaveResult 结构相似的内容
saveBundle 是一个 JSON 包,您可能不想自己解包。幸运的是,您可以从 ContextProvider 派生一个类,您可以使用它来将 saveBundle 转换为“SaveMap”,这是一个包含 EntityInfo 对象的字典,这几乎是任何人在分析变更集时都希望使用的对象用于验证和保存。
以下方法可能会奏效:
using System;
using System.Collections.Generic;
using System.Data;
using Breeze.ContextProvider;
using Newtonsoft.Json.Linq;
public class SaveBundleToSaveMap : ContextProvider
{
// Never create a public instance
private SaveBundleToSaveMap(){}
/// <summary>
/// Convert a saveBundle into a SaveMap
/// </summary>
public static Dictionary<Type, List<EntityInfo>> Convert(JObject saveBundle)
{
var dynSaveBundle = (dynamic) saveBundle;
var entitiesArray = (JArray) dynSaveBundle.entities;
var provider = new SaveBundleToSaveMap();
var saveWorkState = new SaveWorkState(provider, entitiesArray);
return saveWorkState.SaveMap;
}
// override abstract members but DO NOT USE ANY OF THEM
}
然后由您决定如何使用“SaveMap”并分派到您的业务逻辑。
SaveResult 是一个简单的结构:
public class SaveResult {
public List<Object> Entities; // each of the entity type you serialize to the client
public List<KeyMapping> KeyMappings;
public List<Object> Errors;
}
public class KeyMapping {
public String EntityTypeName;
public Object TempValue;
public Object RealValue;
}
按原样使用这些类或构建您自己的类。 Breeze 客户端关心的是 JSON,而不是这些类型。