已添加具有相同键的项目 - 仅在发布模式下

本文关键字:布模式 模式 添加 项目 | 更新日期: 2023-09-27 18:31:32

专家,

我在运行时第一次使用实体框架函数时就得到了这个 System.ArgumentException已经添加了具有相同键的项目)。奇怪的是:如果我使用调试模式,它可以正常工作。编译相同的代码后,在发布模式下不做任何更改后,它会立即崩溃,但本文顶部提到了异常。

有谁知道更多关于这种奇怪的行为?我该如何解决它?我无法向我的客户推出调试版本:(

此时会引发异常:

try
{
  var blub = context.ExecuteStoreQuery<int>(QueryString);
}
catch (Exception ex)
{
  // ...
}    

堆栈跟踪:

System.ArgumentException: An item with the same key has already been added.
   at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boo
lean add)
   at System.Data.Metadata.Edm.ObjectItemAttributeAssemblyLoader.LoadRelationshi
pTypes()
   at System.Data.Metadata.Edm.ObjectItemAttributeAssemblyLoader.LoadTypesFromAs
sembly()
   at System.Data.Metadata.Edm.ObjectItemAssemblyLoader.Load()
   at System.Data.Metadata.Edm.ObjectItemAttributeAssemblyLoader.Load()
   at System.Data.Metadata.Edm.AssemblyCache.LoadAssembly(Assembly assembly, Boo
lean loadReferencedAssemblies, ObjectItemLoadingSessionData loadingData)
   at System.Data.Metadata.Edm.AssemblyCache.LoadAssembly(Assembly assembly, Boo
lean loadReferencedAssemblies, ObjectItemLoadingSessionData loadingData)
   at System.Data.Metadata.Edm.AssemblyCache.LoadAssembly(Assembly assembly, Boo
lean loadReferencedAssemblies, ObjectItemLoadingSessionData loadingData)
   at System.Data.Metadata.Edm.AssemblyCache.LoadAssembly(Assembly assembly, Boo
lean loadReferencedAssemblies, ObjectItemLoadingSessionData loadingData)
   at System.Data.Metadata.Edm.AssemblyCache.LoadAssembly(Assembly assembly, Boo
lean loadReferencedAssemblies, KnownAssembliesSet knownAssemblies, EdmItemCollec
tion edmItemCollection, Action`1 logLoadMessage, Object& loaderCookie, Dictionar
y`2& typesInLoading, List`1& errors)
   at System.Data.Metadata.Edm.ObjectItemCollection.LoadAssemblyFromCache(Object
ItemCollection objectItemCollection, Assembly assembly, Boolean loadReferencedAs
semblies, EdmItemCollection edmItemCollection, Action`1 logLoadMessage)
   at System.Data.Metadata.Edm.MetadataWorkspace.ImplicitLoadAssemblyForType(Typ
e type, Assembly callingAssembly)
   at System.Data.Objects.ObjectContext.ExecuteStoreQueryInternal[TElement](Stri
ng commandText, String entitySetName, MergeOption mergeOption, Object[] paramete
rs)

已添加具有相同键的项目 - 仅在发布模式下

首先,确保即使你做了一个干净的发布版本,也会遇到错误(我的意思是在运行构建之前没有二进制文件,只有源代码)。如果没有,请修复项目设置(例如,隔离调试和发布生成目标文件夹)。

如果错误只发生一次,之后应用程序运行正常,则一定有一些同步问题。虽然这很奇怪,因为元数据加载似乎是同步的。但无论如何,EF 对象都不是线程安全的。不要在跨线程方案中使用它们。

如果上面说的没有帮助,那么也许我的研究结果会对你有所帮助。下面是与错误相关的 EF 源代码摘录:

//---------------------------------------------------------------------- 
// <copyright file="ObjectItemAttributeAssemblyLoader.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Objects.DataClasses;
using System.Diagnostics; 
using System.Reflection;
namespace System.Data.Metadata.Edm 
{
  /// <summary> 
  /// Class for representing a collection of items for the object layer.
  /// Most of the implemetation for actual maintainance of the collection is
  /// done by ItemCollection
  /// </summary> 
  internal sealed class ObjectItemAttributeAssemblyLoader :
      ObjectItemAssemblyLoader
  { 
    // ...
    /// <summary>
    /// This method loads all the relationship type that this entity takes part in
    /// </summary> 
    /// <param name="entityType"></param>
    /// <param name="context"></param> 
    private void LoadRelationshipTypes() 
    {
      foreach (EdmRelationshipAttribute roleAttribute in
               SourceAssembly.GetCustomAttributes(typeof(EdmRelationshipAttribute), false /*inherit*/)) 
      {
        // Check if there is an entry already with this name
        if (TryFindNullParametersInRelationshipAttribute(roleAttribute))
        { 
          // don't give more errors for these same bad parameters
          continue; 
        } 
        bool errorEncountered = false; 
        // return error if the role names are the same
        if (roleAttribute.Role1Name == roleAttribute.Role2Name)
        { 
          SessionData.EdmItemErrors.Add(new EdmItemError(
              System.Data.Entity.Strings.SameRoleNameOnRelationshipAttribute(roleAttribute.RelationshipName, roleAttribute.Role2Name),
                       null)); 
          errorEncountered = true; 
        }

        if (!errorEncountered)
        {
          AssociationType associationType = new AssociationType(
            roleAttribute.RelationshipName, roleAttribute.RelationshipNamespaceName,
            roleAttribute.IsForeignKey, DataSpace.OSpace); 
          SessionData.TypesInLoading.Add(associationType.FullName, associationType);
          TrackClosure(roleAttribute.Role1Type); 
          TrackClosure(roleAttribute.Role2Type); 
          // prevent lifting of loop vars 
          string r1Name = roleAttribute.Role1Name;
          Type r1Type = roleAttribute.Role1Type;
          RelationshipMultiplicity r1Multiplicity = roleAttribute.Role1Multiplicity;
          AddTypeResolver(() => 
            ResolveAssociationEnd(associationType, r1Name, r1Type, r1Multiplicity));
          // prevent lifting of loop vars 
          string r2Name = roleAttribute.Role2Name;
          Type r2Type = roleAttribute.Role2Type; 
          RelationshipMultiplicity r2Multiplicity = roleAttribute.Role2Multiplicity;
          AddTypeResolver(() =>
            ResolveAssociationEnd(associationType, r2Name, r2Type, r2Multiplicity));
          // get assembly entry and add association type to the list of types in the assembly
          Debug.Assert(!CacheEntry.ContainsType(associationType.FullName), "Relationship type must not be present in the list of types"); 
          CacheEntry.TypesInAssembly.Add(associationType); 
        }
      } 
    }
    // ...
  }
}

该方法中使用的唯一字典是 SessionData.TypesInLoading 。关键是RelationshipNameRelationshipNamespaceName的组合。有趣的是,注释说他们检查重复的键,但该方法TryFindNullParametersInRelationshipAttribute只检查属性的属性是否null。我想这是一个错误。

但更重要的是,所描述的错误一定发生了,因为程序集中的某个地方有多个EdmRelationshipAttributeRelationshipName属性和RelationshipNamespaceName属性的组合相等。可能有多种原因:

  1. EDMX 文件不正确。
  2. 不当复制的程序集,
  3. 发布配置将其生成结果输出到与调试配置相同的文件夹,
  4. 手动生成 EF 映射程序集时出错,
  5. 等。

不幸的是,抓住破裂关系的名字将非常困难。您可能必须在 System.Data.Metadata.Edm.ObjectItemAttributeAssemblyLoader.LoadRelationshipTypes() 处设置断点并在反汇编中跟踪它。我会说这几乎是不可能的,因为Dictionary.Insert方法即将被调用很多次。

如果所有这些仍然不能建议解决方案,那么您确实需要准备问题的重现并将其发布在此处。否则没有人能够提供帮助。