12

我已经被这个问题困扰了一个多星期了。希望有人能指出我正确的方向。

我首先简要描述一下我的架构。

资产 1--->1 地址 *-->1 地区 *-->1 地区 *-->1 国家

包 1-->* 资产

使用自我跟踪实体 (STE) + WCF。

脚步:

  1. 调用数据存储以获取资产列表。
  2. 调用数据存储以获取软件包列表。
  3. 用户选择一个包并为其分配一些资产。
  4. 保存包。

在第 2 步中,调用使用地址的预先加载。

from p in context.Assets.Include("Address.Area.Region.Country")

这是尝试调用时的错误

context.Packages.ApplyChanges(package)

AcceptChanges 无法继续,因为对象的键值与 ObjectStateManager 中的另一个对象冲突。在调用 AcceptChanges 之前确保键值是唯一的。

编辑

在窥探之后,我发现这是一个 STE 问题。问题是您无法保留包含此处概述的同一实体的多个实例的图形。这是我的问题。

如何将实体添加到我的实体集合中。新实体可能具有包含与集合中已有的相同键的相关实体。即添加可能包含相同地址、区域、地区或国家实体的新资产。

这是我的约束:

  1. 我必须使用导航集合,因为它会影响 UI。
  2. 我无法预取将涉及的所有实体,因为数据集太大了。
  3. 我必须能够随时拍摄实体的快照,以便保留历史记录并使用它来“撤消”任何更改。

我知道Diego B Vega建议的可能解决方案,但这些不是我可以用于我的解决方案的选项。有没有人有其他想法?

4

5 回答 5

8

如果您知道我的意思,您是否考虑过放弃 ORM-s 并恢复正常访问:-)

不是开玩笑——当你遇到一个像这样的问题(闻起来更像是 ORM 错误)时,你可能已经推出了自己的 5-10 个函数来进行正常的 sproc 调用和更轻松的数据类型转换,然后你已恢复完全控制,并且不会被库所困,这些库将需要 5 年才能稳定下来。

特别是因为您似乎拥有非常干净的架构 - 意味着非常简单的查询和直接的更新。

于 2010-08-05T12:18:45.697 回答
8

仅供参考,我写了一篇博客文章,对我在 EF 论坛中已经回复的内容提出了一些额外的建议。是博客文章。

于 2010-10-06T16:52:43.440 回答
3

我遇到了同样的问题,最后想出了一个解决方案。基本思想是防止某些导航类类型附加到 ObjectContext。这是我所做的:

  1. 修改了 context.tt 模板以使 SelfTrackingEntitiesContextExtensions 类部分化。
  2. 将 2 个 ApplyChanges 函数复制到新创建的 Custom.Context.Extension.cs 并将它们重命名为 CustomApplyChanges。每个都有一个额外的参数作为类型数组

public static void CustomApplyChanges(this ObjectContext context, string entitySetName, TEntity entity, Type[] excludeTypes ) where TEntity : IObjectWithChangeTracker

  1. 向 for 循环添加条件以排除 excludeTypes 数组中包含的任何类类型。

区域句柄初始实体状态

foreach (IObjectWithChangeTracker changedEntity in entityIndex.AllEntities.Where(x => x.ChangeTracker.State == ObjectState.Deleted && !excludeTypes.Contains(x.GetType()))) { HandleDeletedEntity(context, entityIndex, allRelationships, changedEntity); }

foreach (IObjectWithChangeTracker changedEntity in entityIndex.AllEntities.Where(x => x.ChangeTracker.State != ObjectState.Deleted && !excludeTypes.Contains(x.GetType()))) { HandleEntity(context, entityIndex, allRelationships, changedEntity); }

端区

  1. 用途

Type[] excludeTypes = { typeof(Asset), typeof(Address), typeof(Region)};

rep.Entities.CustomApplyChanges(entity, excludeTypes); var changedEntry = rep.Context.ObjectStateManager.GetObjectStateEntries>(System.Data.EntityState.Added | System.Data.EntityState.Modified | System.Data.EntityState.Deleted); foreach (var e in changedEntry) { if (excludeTypes.Any(c => c == e.Entity.GetType())) { rep.Context.Detach(e.Entity); //分离未更改的对象 } }

于 2010-08-13T18:46:11.100 回答
1

我通过设置重置外键 ID 解决了这个问题,这需要在保存之前将导航值设置为空。

......像这样的东西:

var countryToId = address.CountryToId;
var countryFromId = address.CountryFromId;
documentAddress.CountryTo = null;
documentAddress.CountryFrom = null;
documentAddress.CountryToId = countryToId;
documentAddress.CountryFromId = countryFromId;
于 2013-05-11T13:14:56.010 回答
0

我收到此错误是因为我正在删除实体的记录,重新播种,然后用新数据重新填充实体。

由于在此实体上启用了自我跟踪,因此它不允许添加具有相同键的记录,即使具有该键的记录已被删除。

由于在这种情况下我不需要自我跟踪,因此我将其禁用为:

dbcontext.entity.MergeOption = System.Data.Objects.MergeOption.NoTracking;
于 2014-04-22T11:23:24.983 回答