2012-10-24 24 views
4

由於我已切換到.net 4.5和EF 5.0,我已經開始使用枚舉映射。 在我的項目中,我先使用模型。因爲所有的枚舉都是早先聲明的,所以我決定在用戶​​選項「引用外部類型」時將字段轉換爲EDM中的枚舉。一切工作正常,但是當我試圖像引用外部類型枚舉幷包含方法

public enum SomeEnum : int 
{ 
    value1 = 0, 
    value2 = 1 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     TestDbEntities context = new TestDbEntities(); 
     var enumList = new List<SomeEnum>() { SomeEnum.value1, SomeEnum.value2 }; 
     var items = context.Table1.Where(e => enumList.Contains(e.EnumField)); 
     foreach (var item in items) 
     { 
      Console.Write(item.Id); 
     } 
     context.Dispose(); 
    } 
} 

我得到的ArgumentException有消息執行代碼:

The type 'SomeEnum' does not match the EDM enumeration type 'SomeEnum' or its underlying type 'Int32' Parameter name: value.  

什麼是有線的是,當我不使用外部參考一切類型沒關係。我理解其背後是什麼在EDM,但我不明白爲什麼這個代碼工作時,枚舉在模型定義,後來由T4

產生
<EntityContainer Name="TestDbEntities" p1:LazyLoadingEnabled="true"> 
     <EntitySet Name="Table1" EntityType="TestDbModel.Table1" /> 
    </EntityContainer> 
    <EntityType Name="Table1"> 
     <Key> 
     <PropertyRef Name="Id" /> 
     <PropertyRef Name="EnumField" /> 
     </Key> 
     <Property Name="Id" Type="Int32" Nullable="false" /> 
     <Property Name="EnumField" Type="TestDbModel.SomeEnum" Nullable="false" /> 
    </EntityType> 
    <EnumType Name="SomeEnum" a:ExternalTypeName="ConsoleApplication1.SomeEnum" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" /> 

我想用引用外部類型,但是這是一些侷限性。我知道我可以投入基礎類型,但這是一種破解。

----編輯 這裏是一個堆棧跟蹤

at System.Data.Common.CommandTrees.ExpressionBuilder.Internal.ArgumentValidation.ValidateConstant(TypeUsage constantType, Object value) 
at System.Data.Objects.ELinq.ExpressionConverter.ConstantTranslator.TypedTranslate(ExpressionConverter parent, ConstantExpression linq) 
at System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq) 
at System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq) 
at System.Data.Objects.ELinq.ExpressionConverter.NewArrayInitTranslator.<>c__DisplayClass88.<TypedTranslate>b__86(Expression e) 
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext() 
at System.Data.Common.CommandTrees.ExpressionBuilder.Internal.EnumerableValidator`3.Validate(IEnumerable`1 argument, String argumentName, Int32 expectedElementCount, Boolean allowEmpty, Func`3 map, Func`2 collect, Func`3 deriveName) 
at System.Data.Common.CommandTrees.ExpressionBuilder.Internal.EnumerableValidator`3.Validate() 
at System.Data.Common.CommandTrees.ExpressionBuilder.Internal.ArgumentValidation.CreateExpressionList(IEnumerable`1 arguments, String argumentName, Boolean allowEmpty, Action`2 validationCallback) 
at System.Data.Common.CommandTrees.ExpressionBuilder.Internal.ArgumentValidation.ValidateNewCollection(IEnumerable`1 elements, DbExpressionList& validElements) 
at System.Data.Common.CommandTrees.ExpressionBuilder.DbExpressionBuilder.CreateNewCollection(IEnumerable`1 elements) 
at System.Data.Objects.ELinq.ExpressionConverter.NewArrayInitTranslator.TypedTranslate(ExpressionConverter parent, NewArrayExpression linq) 
at System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq) 
at System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq) 
at System.Data.Objects.ELinq.ExpressionConverter.ConstantTranslator.TypedTranslate(ExpressionConverter parent, ConstantExpression linq) 
at System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq) 
at System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq) 
at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.ContainsTranslator.TranslateContains(ExpressionConverter parent, Expression sourceExpression, Expression valueExpression) 
at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.ContainsTranslator.Translate(ExpressionConverter parent, MethodCallExpression call) 
at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod) 
at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq) 
at System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq) 
at System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq) 
at System.Data.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input) 
at System.Data.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input, DbExpressionBinding& binding) 
at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, DbExpression& source, DbExpressionBinding& sourceBinding, DbExpression& lambda) 
at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call) 
at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod) 
at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq) 
at System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq) 
at System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq) 
at System.Data.Objects.ELinq.ExpressionConverter.Convert() 
at System.Data.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption) 
at System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption) 
at System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() 
at System.Data.Entity.Internal.Linq.InternalQuery`1.GetEnumerator() 
at System.Data.Entity.Infrastructure.DbQuery`1.System.Collections.Generic.IEnumerable<TResult>.GetEnumerator() 
at ConsoleApplication1.Program.Main(String[] args) in c:\Users\Pawel\Documents\Visual Studio 2012\Projects\ClassLibrary1\ConsoleApplication1\Program.cs:line 22 
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) 
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) 
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 
at System.Threading.ThreadHelper.ThreadStart_Context(Object state) 
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
at System.Threading.ThreadHelper.ThreadStart() 
+0

你能發佈完整的stacktrace嗎?你可以用'e.EnumField == SomeEnum.value1 ||替換enumList.Contains(e.EnumField))嗎? e.EnumField == SomeEnum.value2'並讓我知道它是否有效。我希望您檢查的另一件事是,如果將CLR類型枚舉成員添加到CSDL枚舉類型,它是否可以工作。我懷疑這裏可能有一個錯誤。 – Pawel

+0

要複製我的問題,您可以簡單地創建一些EDM模型,然後使用「引用外部類型」選項將某些int轉換爲枚舉。 解決方案:e.EnumField == SomeEnum.value1 || e.EnumField == SomeEnum.value2的作品,但由於我已經重構現有的代碼有枚舉,它將很難找到所有的地方。 映射CLR類型枚舉成員CSDL枚舉類型就像一個魅力,就像我之前提到的 –

+0

更新我的帖子關於EF5中的枚舉以反映這個錯誤。 – Pawel

回答

4

這是一個錯誤。我將它提交到EntityFramework Codeplex站點:http://entityframework.codeplex.com/workitem/623。目前,解決方法是使用||或者在EDM枚舉類型中指定CLR枚舉類型中的所有成員。 設置外部枚舉類型將註釋添加到EDM枚舉類型(a:ExternalTypeName =「ConsoleApplication1.SomeEnum」),它告訴代碼gen不生成此類型,但使用生成的代碼中使用該類型的任何地方的屬性值。如果沒有此註釋,將生成與EDM枚舉類型完全匹配的CLR枚舉。順便說一句。我前一段時間寫了一篇關於EF5和外部枚舉類型的博文。你可以在這裏找到它:http://blog.3d-logic.com/2012/09/11/using-exisiting-enum-types-in-entity-framework-5/。我會在博客上添加有關錯誤的信息。隨意評論它。

+0

你知道這是否有一個MS修復已經? – Martijn

+0

它已在EF6中修復。 – Pawel

+0

因此,在當前可用的EF6版本中,您不必指定edmx中的所有枚舉值? – Martijn

2

不是一個直接的解決方案,但是這種解決方法正在滿足我的要求。

var enumList = new List<int>() { (int)SomeEnum.value1, (int)SomeEnum.value2 }; 
var items = context.Table1.Where(e => enumList.Contains((int)e.EnumField));