我创建了自己的ContextProvider,子类来自EFContextProvider。在BeforeSaveEntity中,我正在运行一些业务逻辑来验证事务。我需要更新为“全部或全部”,因此如果集合中的第三个实体未通过验证,则应丢弃整个批次,即使我已经为前两个实体返回“true”。
我有一个类级属性,在任何实体失败时都会被设置。在BeforeSaveEntities的最终检查中,我可以获得该标志的值。
我认为这是我可以中止更新的地方,但不知道如何。我清除地图吗?或抛出错误?
另外,我需要重新查询数据库以获取验证例程。我已经阅读了一些关于创建上下文实例的帖子,以便查询当前值。是否有一些关于这样做的文档,或者我需要注意的问题?
感谢
答案 0 :(得分:2)
在 BeforeSaveEntities 调用中,您可以抛出 EntityErrorsException :这是一个示例,如果尝试在保存中保存任何“Order”对象,则会抛出异常捆绑:
[HttpPost]
public SaveResult SaveWithEntityErrorsException(JObject saveBundle) {
ContextProvider.BeforeSaveEntitiesDelegate = ThrowEntityErrorsException;
return ContextProvider.SaveChanges(saveBundle);
}
private Dictionary<Type, List<EntityInfo>> ThrowEntityErrorsException(Dictionary<Type, List<EntityInfo>> saveMap) {
List<EntityInfo> orderInfos;
if (saveMap.TryGetValue(typeof(Order), out orderInfos)) {
var errors = orderInfos.Select(oi => {
return new EntityError() {
EntityTypeName = typeof(Order).FullName,
ErrorMessage = "Cannot save orders with this save method",
ErrorName = "WrongMethod",
KeyValues = new object[] { ((Order) oi.Entity).OrderID },
PropertyName = "OrderID"
};
return new EFEntityError(oi, "WrongMethod", "Cannot save orders with this save method", "OrderID");
});
var ex = new EntityErrorsException("test of custom exception message", errors);
// if you want to see a different error status code use this.
// ex.StatusCode = HttpStatusCode.Conflict; // Conflict = 409 ; default is Forbidden (403).
throw ex;
}
return saveMap;
}
并且您应该使用BeforeSaveEntities而不是BeforeSaveEntity,因为您的保存逻辑变得更加复杂。
答案 1 :(得分:0)
我要求对客户端上已更改的实体执行服务器端计算 - 不保存 - 并将结果返回给客户端。我提出的基于Breeze named saves的解决方案在这种情况下也很有用。
我将以下方法添加到Breeze控制器的基类中。
protected SaveResult OverrideSaveChanges(JObject saveBundle, Action<List<object>> action, bool shouldSave = false)
{
var saveChangesDelegate = new SaveChangesOverride(action, shouldSave);
return saveChangesDelegate.Execute(saveBundle, ContextProvider);
这允许具体的控制器非常简单地实现命名保存。 saveBundle加上Action<List<object>>
将传递给OverrideSaveChanges方法。该操作可以对所需的实体进行任何修改,并且这些更改将传播回客户端。列表中的对象是客户端识别为具有更改的实体,并将其发送到服务器以进行命名保存。 (可选)您可以传递值为true的shouldSave参数以保存实体 - 默认值为false。
OverrideChanges委托给SaveChangesOverride进行大部分繁重的工作。
public class SaveChangesOverride
{
public SaveChangesOverride(Action<List<object>> action, bool shouldSave = false)
{
Action = action;
ShouldSave = shouldSave;
}
private readonly Action<List<object>> Action;
private readonly bool ShouldSave;
public List<object> Entities;
public SaveResult Execute(JObject saveBundle, ContextProvider contextProvider)
{
contextProvider.BeforeSaveEntitiesDelegate = OnBeforeSaveEntities;
contextProvider.SaveChanges(saveBundle);
return new SaveResult
{
Entities = Entities,
KeyMappings = new List<KeyMapping>()
};
}
private Dictionary<Type, List<EntityInfo>> OnBeforeSaveEntities(Dictionary<Type, List<EntityInfo>> arg)
{
Entities = arg.SelectMany(x => x.Value).Select(x => x.Entity).ToList();
Action(Entities);
if (!ShouldSave)
{
return new Dictionary<Type, List<EntityInfo>>();
}
return arg;
}
}
虽然我们可以访问saveBundle中所有已更改的实体,但实际上在OnBeforeSaveChanges中执行修改允许我们使用实体而不是JObject。
此外,无论我们是否希望保存实体,都必须调用contextProvider.SaveChanges。这是触发OnBeforeSaveEntities被调用的原因。为了确保尽管调用SaveChanges(如果这是所需的)不保存实体,而不是从OnBeforeSaveEntities返回arg,则返回一个空字典。
为确保更改将其返回给客户端,对实体的引用将保存在OnBeforeSaveEntities中。这在Execute中用于准备使用修改后的实体填充的SaveResult。