Entity framework 导入项()后导航属性未正确重新连接
背景: 我使用文档中描述的SandboxManager格式将实体导出到第二个管理器以进行更改,然后将实体导入回主管理器。我使用createEmptyCopy从主管理器的副本创建页面初始化沙盒,并为沙盒提供相同的元数据,而不提供任何实体 在导出过程中,我通过以下方式传递实体:Entity framework 导入项()后导航属性未正确重新连接,entity-framework,breeze,Entity Framework,Breeze,背景: 我使用文档中描述的SandboxManager格式将实体导出到第二个管理器以进行更改,然后将实体导入回主管理器。我使用createEmptyCopy从主管理器的副本创建页面初始化沙盒,并为沙盒提供相同的元数据,而不提供任何实体 在导出过程中,我通过以下方式传递实体: function exportEntityToSandbox(entity) { var exportData = STEP.EntityManager.exportEntities([entity], false
function exportEntityToSandbox(entity) {
var exportData = STEP.EntityManager.exportEntities([entity], false);
var result = STEP.SandboxManager.importEntities(exportData,
{ mergeStrategy: breeze.MergeStrategy.OverwriteChanges });
// ImportEntities changes the service name so revert it back
STEP.SandboxManager.setProperties({
dataService: new breeze.DataService({
serviceName: 'api/Sandbox',
hasServerMetadata: false
})
});
return result.entities[0];
};
我目前正在与该实体合作:
public class License
{
public int ID { get; set; }
public int LicenseTypeID { get; set; }
public virtual LicenseType LicenseType { get; set; }
public int ExternalProductID { get; set; }
public virtual ExternalProduct ExternalProduct { get; set; }
public int? LicensesPurchased { get; set; }
public int? LicensesAllocated { get; set; }
public string AllocationDescription { get; set; }
public bool DeletedFlag { get; set; }
}
public LicenseMap()
{
this.HasKey(t => t.ID);
this.Property(t => t.ID)
.HasColumnName("ID")
.HasColumnType("int")
.IsRequired();
this.Property(t => t.LicenseTypeID)
.HasColumnName("LICENSE_TYPE_ID")
.HasColumnType("int")
.IsRequired();
this.Property(t => t.ExternalProductID)
.HasColumnName("PRODUCT_ID")
.HasColumnType("int")
.IsRequired();
this.Property(t => t.LicensesPurchased)
.HasColumnName("LICENSES_PURCHASED")
.HasColumnType("int")
.IsOptional();
this.Property(t => t.LicensesAllocated)
.HasColumnName("LICENSES_ALLOCATED")
.HasColumnType("int")
.IsOptional();
this.Property(t => t.AllocationDescription)
.HasColumnName("ALLOCATION_DESCRIPTION")
.HasColumnType("varchar")
.HasMaxLength(Int32.MaxValue)
.IsOptional();
this.Property(t => t.DeletedFlag)
.HasColumnName("DELETED_FLAG")
.HasColumnType("bit")
.IsRequired();
this.ToTable("LICENSE");
}
}
以及该实体的地图:
public class License
{
public int ID { get; set; }
public int LicenseTypeID { get; set; }
public virtual LicenseType LicenseType { get; set; }
public int ExternalProductID { get; set; }
public virtual ExternalProduct ExternalProduct { get; set; }
public int? LicensesPurchased { get; set; }
public int? LicensesAllocated { get; set; }
public string AllocationDescription { get; set; }
public bool DeletedFlag { get; set; }
}
public LicenseMap()
{
this.HasKey(t => t.ID);
this.Property(t => t.ID)
.HasColumnName("ID")
.HasColumnType("int")
.IsRequired();
this.Property(t => t.LicenseTypeID)
.HasColumnName("LICENSE_TYPE_ID")
.HasColumnType("int")
.IsRequired();
this.Property(t => t.ExternalProductID)
.HasColumnName("PRODUCT_ID")
.HasColumnType("int")
.IsRequired();
this.Property(t => t.LicensesPurchased)
.HasColumnName("LICENSES_PURCHASED")
.HasColumnType("int")
.IsOptional();
this.Property(t => t.LicensesAllocated)
.HasColumnName("LICENSES_ALLOCATED")
.HasColumnType("int")
.IsOptional();
this.Property(t => t.AllocationDescription)
.HasColumnName("ALLOCATION_DESCRIPTION")
.HasColumnType("varchar")
.HasMaxLength(Int32.MaxValue)
.IsOptional();
this.Property(t => t.DeletedFlag)
.HasColumnName("DELETED_FLAG")
.HasColumnType("bit")
.IsRequired();
this.ToTable("LICENSE");
}
}
我只在导出ExternalProduct时传入许可证实体,而LicenseType导航实体不会传递到沙箱。但是,所有ExternalProducts和LicenseTypes都会在页面初始化时加载到主管理器中。因此在工作流中,我从下拉列表中选择ExternalProduct并只更新ExternalProductId,因为ExternalProduct本身不在沙箱中
问题:
我面临的问题是当实体被导出回主管理器时:
function save(id, manager, tag) {
manager = manager || STEP.SandboxManager;
return manager.saveChanges()
.then(saveSucceeded)
.fail(saveFailed);
function saveSucceeded(data) {
var exportData = STEP.SandboxManager.exportEntities(data.entities, false);
STEP.EntityManager.importEntities(exportData,
{ mergeStrategy: breeze.MergeStrategy.OverwriteChanges });
// ImportEntities changes the service name
// Revert it back
STEP.EntityManager.setProperties({
dataService: new breeze.DataService({
serviceName: 'api/Datamart',
hasServerMetadata: false
})
});
// Get a reference to the same entity in the Sandbox and update observable
var entityKey = data.entities[0].entityAspect.getKey();
var type = entityKey.entityType.shortName;
var entityManagerEntity = STEP.EntityManager.getEntityByKey(type, id);
};
function saveFailed(msg) {
// Do stuff
};
};
该实体在编辑过程中更改了新的ExternalProductId,但仍具有旧的ExternalProduct导航实体。新的导航实体没有连接到许可证,即使我知道它在缓存中。导航属性仍然指向旧的实体属性License.ExternalProductId不等于License.ExternalProduct.ID
所以,我是不是太期待Breeze在导入时重新布线,每次都需要手动完成
我认为这可能是我的EF定义的一个问题,并尝试将其中每一个添加到LicenseMap中,但没有成功:
this.HasRequired(m => m.ExternalProduct)
.WithOptional()
.Map(m => m.MapKey("ExternalProductID"));
this.HasRequired(t => t.ExternalProduct
.WithMany()
.HasForeignKey(t => t.ExternalProductID)
.WillCascadeOnDelete(false);
这是仅与许可证实体上的导航属性的必需关系。
我使用的是Breeze v1.4.11
编辑:
我只是确定这在实体图中:
this.HasRequired(t => t.ExternalProduct)
.WithMany()
.HasForeignKey(t => t.ExternalProductID);
并测试了这个简单的代码片段:
license.ExternalProductID(816);
var test = license.ExternalProduct();
直接设置ID后,导航实体ExternalProduct的测试变量仍然不变。根据Breeze文档,除非我做错了什么,否则应该更新导航实体。我弄明白了这一点 问题是缓存中没有所有ExternalProducts,因此在更改导航属性ID时,关联的ExternalProduct实体无法从新ID连接。当我确保新ExternalProduct在缓存中时,更改许可证上的ID会正确更新ExternalProduct
我可以说,当License.ExternalProductID被更改为不在缓存中但我偏离主题的实体的值时,Breeze应该将ExternalProduct设置为null。您发现了一个bug。将FK设置为值应导致刷新相应的导航属性。如果对应的实体在缓存中,则该操作将正常工作。不幸的是,如果对应的实体不在缓存中,Breeze v.1.5.1不会像它应该的那样使导航属性无效
那件事解决后我会回来的。我们会跳上去的。请继续关注。您是说Breeze在ExternalProduct中留下了正确的实体吗?那将是一个错误。我会努力纠正的。正如我在下面解释的那样,我们将解决这个问题。