【问题标题】:Navigation Properties not re-wired correctly after importEntities()importEntities() 后导航属性未正确重新连接
【发布时间】:2014-11-06 00:41:35
【问题描述】:

背景:

我正在使用文档中描述的 SandboxManager 格式将我的实体导出到第二个管理器进行更改,然后将实体导入回主管理器。我正在使用 createEmptyCopy() 从主管理器的副本在页面初始化时创建沙箱,为沙箱提供相同的元数据并且没有实体。

在导出过程中,我通过这种方式传递实体:

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");

    }
}

我只在导出过程中传入了许可证实体——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);

这只是许可实体上的导航属性的必需关系。 我正在使用微风 v1.4.11

编辑:

我只是确定这是在实体映射中:

this.HasRequired(t => t.ExternalProduct)
    .WithMany()
    .HasForeignKey(t => t.ExternalProductID);

并测试了这个简单的编码sn-p:

license.ExternalProductID(816);
var test = license.ExternalProduct();

并且直接设置ID后导航实体ExternalProduct的测试变量依然没有变化。根据 Breeze 文档,导航实体应该更新,除非我做错了什么?

【问题讨论】:

    标签: entity-framework breeze


    【解决方案1】:

    您发现了一个错误。将 FK 设置为一个值应该会导致相应的导航属性被刷新。如果相应的实体在缓存中,这将正常工作。不幸的是,如果相应的实体不在缓存中,Breeze v.1.5.1 不会像应有的那样将导航属性置空。

    问题解决后我会回来的。我们将继续前进。敬请期待。

    【讨论】:

      【解决方案2】:

      我想通了。

      问题是我没有缓存所有的 ExternalProducts,因此在更改导航属性 ID 时,关联的 ExternalProduct 实体无法从新 ID 连接。当我确保新的 ExternalProduct 在缓存中时,更改许可证上的 ID 会正确更新 ExternalProduct。

      我可以争辩说,当 License.ExternalProductID 更改为不在缓存中但我离题的实体的值时,Breeze 应该将 ExternalProduct 设置为 null。

      【讨论】:

      • 您是说 Breeze 在 ExternalProduct 中留下了不正确的实体吗?那将是一个错误。我会尝试重现。
      • 对。正如我在下面解释的那样,我们将解决这个问题。
      猜你喜欢
      • 2020-12-16
      • 2014-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多