C# 如何将Breeze与通用工作单元和存储库一起使用?
使用此选项: 以及以下一组博客帖子: 我们正试图将这些存储库与C# 如何将Breeze与通用工作单元和存储库一起使用?,c#,asp.net,asp.net-web-api,odata,breeze,C#,Asp.net,Asp.net Web Api,Odata,Breeze,使用此选项: 以及以下一组博客帖子: 我们正试图将这些存储库与Breeze结合使用,因为它可以很好地处理客户端javascript和OData 我想知道如何将它们与Breeze一起使用,以正确地处理覆盖BeforeSaveEntity 我们在保存过程中需要进行大量的业务逻辑(修改属性,如ModifiedBy,ModifiedTime,CreatedBy,等等),但当我们更改这些属性时,它们不会被breeze更新,因此我们必须在保存后重新查询(我们已经尝试手动映射回更改,但它要求我们复制所有业
Breeze
结合使用,因为它可以很好地处理客户端javascript和OData
我想知道如何将它们与Breeze
一起使用,以正确地处理覆盖BeforeSaveEntity
我们在保存过程中需要进行大量的业务逻辑(修改属性,如ModifiedBy
,ModifiedTime
,CreatedBy
,等等),但当我们更改这些属性时,它们不会被breeze更新,因此我们必须在保存后重新查询(我们已经尝试手动映射回更改,但它要求我们复制所有业务逻辑)
我们的第二个选择是检查每个实体的类型
,然后为其请求正确的存储库,在内部处理保存,然后在客户端上执行新的get请求以获取更新的信息。虽然这很健谈,但我们希望有更好的方法。bypa更新这些对象的正确方法是什么在不返回错误或事后必须重新注册数据的情况下保存数据
任何在保存过程中使用业务逻辑的Breeze示例都会非常有用,特别是如果它发生在服务、存储库或其他地方,而不是直接发生在
BeforeSaveEntity
方法中。这是一个多问题的集合,每个问题都是一个大主题。我能做的最好的事情就是向您指出一些方向
在开始之前,让我解释一下为什么设置“属性如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控制器中实例化BreezeEFContextProvider
。该控制器(或多个控制器)将委托给负责业务逻辑和数据访问的外部类,可能是存储库或工作单元(UoW)类
使用Breeze.NET组件的存储库模式
我们倾向于为模型(通常是POCO)、数据访问(ORM)和web(WebAPI加上客户端资产)项目创建单独的项目。您将在中以及John Papa的Code Camper示例中看到这种分离,该示例是他的Pluralsight课程的同伴“”
这些示例还演示了存储库模式的实现,该模式将多个存储库和UoW的职责混合在一个类中。这对于这些示例中的小模型是有意义的。没有什么可以阻止您将存储库重构为单独的类
我们将我们的repository类与EF数据访问材料放在同一个项目中,因为我们认为为这个小目的创建另一个项目没有特别的价值。如果你决心这样做的话,重构成一个独立的项目并不困难
Breeze和Code Camper示例都集中于Breeze客户端开发。它们在服务器端逻辑上很精简。也就是说,您将在“NorthwindRepository.cs”和“NorthwindEntitySaveGuard.cs”的BeforeSaveEntities
扩展点中找到应用自定义业务逻辑的有价值的线索“DocCode示例中的文件。您将看到如何根据发出请求的用户将保存限制为某些类型以及这些类型的某些记录
如果尝试通过单个端点传递所有保存更改请求,则逻辑可能会非常复杂。你不必那么做。您可以有多个save端点,每个端点专用于特定的业务操作,该业务操作仅限于以高度特定的方式插入/更新/删除少数类型的实体。你可以随心所欲。请参阅中的“命名保存”
随你的便
现在有无数种方法可以实现存储库和UoW模式
你可以按照你所引用的帖子的方式去做。在这种情况下,您不需要Breeze.NET组件。将Web API查询方法(IQueryable
或不)连接到返回IQueryable
(或仅返回对象)的存储库方法非常简单。Web API不必知道您是否在幕后拥有BreezeEFContextProvider
或完全不同的东西
处理Breeze客户端的SaveChanges
请求有点棘手。也许您可以从ContextProvider
或EFContextProvider
派生;也许不是。和方法,尤其是SaveChanges
方法,您将看到需要做些什么,以使Breeze客户端满意,并与希望使用UoW处理更改集保存的方式进行交互
假设您在客户端不做任何更改(这是一个假设,不是给定的…),您可以更改保存协议
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
}
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;
}