我的公司正在更新一款旧产品的UI,使其与现代浏览器兼容等等。我们正在处理的一个限制是,我们无法更改驱动它的数据库。不幸的是,数据库的结构很差,因此,我们必须做一些不太好的事情来实现这一点。
缺点之一是添加、删除、更新等数据的过程都是通过存储过程完成的。由于有太多的特殊情况和奇怪的行为,我们无法在现有的时间内避开它们。因此,我尝试在这些存储过程适用时调用它们。这么多是有效的,但Breeze似乎对我所做的不满意。
更具体地说,在添加特定实体时,我会进入自定义EF存储库的add方法,调用用于添加的存储过程,并将实体的状态设置为不变。它被添加到数据库中,一切都很顺利,直到Breeze试图将它分配的临时负密钥修复为新的真实密钥。不知怎么的,我需要告诉Breeze新密钥是什么,这样它才能解决,但为Breeze四处查找文档并没有让我取得任何进展。有什么想法吗?以下是相关代码。
上下文提供者:
protected override Dictionary<Type, List<EntityInfo>> BeforeSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap)
{
foreach (KeyValuePair<Type, List<EntityInfo>> item in saveMap)
{
foreach (var entityItem in item.Value)
{
if (entityItem.Entity.GetType() == typeof (SerDevice))
{
var repo = new SerDeviceRepository(Context);
var entity = entityItem.Entity as SerDevice;
switch (entityItem.EntityState)
{
case EntityState.Added:
repo.Add(entity);
break;
}
SetEntityState(entityItem, EntityState.Unchanged);
}
}
}
return base.BeforeSaveEntities(saveMap);
}
SerDeviceRepository:
public override void Add(SerDevice entity)
{
var output =
_context.Database.ExecuteSqlCommand(
"exec usp_Device_Add @p0, @p1, @p2, @p3, @p4, @p5",
entity.DeviceName, entity.IpAddress, entity.CommsId,
entity.DeviceTypeId, entity.TemplateId, entity.DeviceStatus);
}
对于其他遇到此问题的人来说,这就是我的解决方案。
在ContextProvider中,您可以选择覆盖一个名为AfterSaveEntities
的方法,该方法的作用与听起来完全一样。这个方法有两个参数:保存映射和键映射列表。这些键映射指示了旧的临时键是什么,新的实际键是什么。由于我通过将实体的状态设置为Unmodified来阻止实体框架执行其常规工作,因此该键没有得到更新,当调用AfterSaveEntities
时,它在实际键点中有临时键,在临时键点中则有null
。
修复方法很简单。只需将真正的密钥移动到临时密钥位置(因为它实际上是临时密钥),并从DbContext
检索刚刚添加到数据库的项的密钥。当保存完成并返回到客户端时,Breeze不会更明智,会认为Entity Framework照常处理业务。
ExampleContextProvider.cs:
protected override void AfterSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap, List<KeyMapping> keyMappings)
{
foreach (var item in saveMap)
{
foreach (var entityItem in item.Value)
{
if (entityItem.Entity.GetType() == typeof (Foo))
{
var entity = entityItem.Entity as Foo;
foreach (var keyMapping in keyMappings)
{
// Assuming your id is an int
if (entity != null && keyMapping.EntityTypeName == entity.GetType().ToString() && entity.Id < 0 && entity.Id == (int) keyMapping.RealValue)
{
// Get the new Foo from the database context
var foo = Context.Foos.First(f => f.FooName == entity.FooName);
// Move the temp to where it should be
// and get the real from the database
keyMapping.TempValue = keyMapping.RealValue;
keyMapping.RealValue = foo.Id;
entity.Id = foo.Id;
}
}
}
}
}
base.AfterSaveEntities(saveMap, keyMappings);
}
如果你有和我一样的问题,我希望这能帮助你!