具有相同键的项目已添加-处于发布模式 [英] An item with the same key has already been added - Just in Release mode

查看:57
本文介绍了具有相同键的项目已添加-处于发布模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

专家

在运行时第一次使用实体框架功能时,我会收到此 System.ArgumentException (已经添加了具有相同键的项).奇怪的是:如果我使用调试模式,它可以正常工作.编译完相同的代码而未在发布模式中进行任何更改后,它立即崩溃,但本文开头提到的异常除外.

I'm getting this System.ArgumentException (An item with the same key has already been added) at the very first use of an entity framework function at runtime. The strange thing: If I'm using debug mode, it works fine. After compiling the same code without any changes made in release mode, it crashes immediatly with exception mentioned at top of this post.

有人对这种奇怪的行为了解更多吗?我该如何解决?我无法向客户推出调试版本:(

Does anyone know more about such a strange behaviour? How can I fix it? I cannot roll out a debug version to my customer :(

此时抛出异常:

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

Stacktrace:

Stacktrace:

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)

推荐答案

首先,即使执行 clean release build ,也要确保您会收到错误消息(我的意思是在运行构建之前没有二进制文件),仅源代码).如果不这样做,则请修复项目设置(例如,隔离调试并释放构建目标文件夹).

First, make sure that you get the error even if you make a clean release build (I mean no binaries before running the build, source code only). If you don't, then fix your project setup (isolate debug and release build target folders for example).

如果错误仅发生一次,然后该应用程序正常运行,则您必须遇到一些同步问题.尽管很奇怪,但是由于元数据加载似乎是同步的.但是无论如何,EF对象都不是线程安全的.不要在跨线程方案中使用它们.

If the error occurs only once and after that the app works fine, you must have some synchronization issues. Although it's quite strange, since metadata loading seems to be synchronized. But in any case, EF objects are not thread-safe. Do not use them in cross-thread scenarios.

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

If the above said doesn't help, then maybe the results of my research will help you. Here's an excerpt from the EF source code that relates to the error:

//---------------------------------------------------------------------- 
// <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 .密钥是 RelationshipName RelationshipNamespaceName 的组合.有趣的是,评论说他们检查重复的键,但是方法 TryFindNullParametersInRelationshipAttribute 仅检查属性的属性不是 null .我想这是一个错误.

The only dictionary used in the method is SessionData.TypesInLoading. The key is a combination of RelationshipName and RelationshipNamespaceName. The funny thing is that a comment says they check for duplicated keys, but the method TryFindNullParametersInRelationshipAttribute checks only that the properties of an attribute are not nulls. I suppose it's a bug.

但是更重要的是,所描述的错误一定已经发生了,因为在程序集中的某个地方,您有多个 EdmRelationshipAttribute ,它们具有相等的 RelationshipName RelationshipNamespaceName <组合/code>属性.可能有多种原因:

But more important is that the described error must have occured because somewhere in your assemblies you have more than one EdmRelationshipAttribute with equal combinations of RelationshipName and RelationshipNamespaceName properties. There might be various reasons:

  1. 不正确的EDMX文件.
  2. 不正确复制的程序集,
  3. 将其构建结果的发布配置发布到与Debug配置相同的文件夹中,
  4. 手动生成EF映射程序集时出现错误,

不幸的是,要了解破裂的关系的名称将非常困难.您可能必须在 System.Data.Metadata.Edm.ObjectItemAttributeAssemblyLoader.LoadRelationshipTypes()处设置一个断点,并在反汇编中对其进行跟踪.我会说这几乎是不可能的,因为 Dictionary.Insert 方法将被称为很多次.

Unfortunately, catching the name of the broken relationship will be very difficult. You'll probably have to set a breakpoint at System.Data.Metadata.Edm.ObjectItemAttributeAssemblyLoader.LoadRelationshipTypes() and trace it in disassembly. I would say it will be nearly impossible because the Dictionary.Insert method is about to be called many times.

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

If all these still don't suggest the solution, then you do need to prepare a repro of your issue and post it here. Otherwise nobody will be able to help.

这篇关于具有相同键的项目已添加-处于发布模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆