Explosion of a compilation BUG [existing solution] caused by VS2015 Update1 update, vs2015update1
A compilation BUG is no problem in the native VS2015, but after it is updated to VS2015 Update1, it is probably because Update1 uses a new compiler, which makes me suffer a lot. This problem also exists in VS2013 Update5, probably using the same compiler.
Next we will reproduce this BUG and use the simplest code to reproduce it.
Test code
A simple interface that defines a "locked" Function
1 public interface ILockable2 {3 bool IsLocked { get; set; }4 }
One entity
Similarly, a simple object definition implements the ILockable interface defined above.
1 public class TestModel : ILockable2 {3 public int Id { get; set; }4 5 public string Name { get; set; }6 7 public bool IsLocked { get; set; }8 }
EF context class
EF context class, which is also extremely simple
1 public class TestDbContext : DbContext2 {3 public TestDbContext()4 : base("default")5 { }6 7 public DbSet<TestModel> TestModels { get; set; }8 }
Interface Extension Method
To facilitate the query of all unlocked data, an IQueryable <T> extension method is defined for the entities implementing the ILockable interface. The Code is also very simple.
1 public static class Extensions2 {3 public static IQueryable<TEntity> Unlocked<TEntity>(this IQueryable<TEntity> source)4 where TEntity : ILockable5 {6 return source.Where(m => !m.IsLocked);7 }8 }
Execute the query code
Next, use the above Code for a simple query
1 internal class Program 2 { 3 private static void Main(string[] args) 4 { 5 try 6 { 7 var db = new TestDbContext(); 8 var models = db.TestModels.Unlocked().ToList(); 9 Console.WriteLine(models.Count);10 }11 catch (Exception ex)12 {13 Console.WriteLine(ex);14 }15 Console.ReadLine();16 }17 }
So far, all the code has been displayed, which is so simple.
Exception display
The Code is also very clear, and there is no obvious problem, but in VS2015 Update1, such an exception will be reported:
"The type" RoslynBugShow. TestModel "cannot be forcibly converted to the type" RoslynBugShow. ILockable ". LINQ to Entities only supports forced conversion of EDM elements or enumeration types. "} Data: {System. collections. listDictionaryInternal} HResult:-2146233067 HelpLink: null InnerException: null Message: "The type" RoslynBugShow. testModel is forcibly converted to the type "RoslynBugShow. ILockable ". LINQ to Entities only supports forced conversion of EDM elements or enumeration types. "Source:" EntityFramework "StackTrace:" In System. data. entity. core. objects. ELinq. expressionConverter. validateAndAdjustCastTypes (TypeUsage toType, TypeUsage fromType, Type toClrType, Type fromClrType) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. getCastTargetType (TypeUsage fromType, Type toClrType, Type fromClrType, Boolean preserveCastForDateTime) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. createCastExpression (DbExpression source, Type toClrType, Type fromClrType) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. convertTranslator. translateUnary (ExpressionConverter parent, UnaryExpression unary, DbExpression operand) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. unaryTranslator. typedTranslate (ExpressionConverter parent, UnaryExpression linq) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. typedTranslator '1. translate (ExpressionConverter parent, Expression linq) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. translateExpression (Expression linq) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. memberAccessTranslator. typedTranslate (ExpressionConverter parent, MemberExpression linq) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. typedTranslator '1. translate (ExpressionConverter parent, Expression linq) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. translateExpression (Expression linq) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. notTranslator. typedTranslate (ExpressionConverter parent, UnaryExpression linq) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. typedTranslator '1. translate (ExpressionConverter parent, Expression linq) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. translateExpression (Expression linq) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. translateLambda (LambdaExpression lambda, DbExpression input) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. translatelamsion( LambdaExpression lambda, DbExpression input, DbExpressionBinding & binding) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. methodCallTranslator. oneLambdaTranslator. translate (ExpressionConverter parent, MethodCallExpression call, DbExpression & source, DbExpressionBinding & sourceBinding, DbExpression & lambda) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. methodCallTranslator. oneLambdaTranslator. translate (ExpressionConverter parent, MethodCallExpression call) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. methodCallTranslator. sequenceMethodTranslator. translate (ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. methodCallTranslator. typedTranslate (ExpressionConverter parent, MethodCallExpression linq) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. typedTranslator '1. translate (ExpressionConverter parent, Expression linq) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. translateExpression (Expression linq) \ r \ n in System. data. entity. core. objects. ELinq. expressionConverter. convert () \ r \ n in System. data. entity. core. objects. ELinq. ELinqQueryState. getExecutionPlan (Nullable '1 forMergeOption) \ r \ n in System. data. entity. core. objects. objectQuery '1. <> c _ DisplayClass7. <GetResults> B _ 6 () \ r \ n in System. data. entity. core. objects. objectContext. executeInTransaction [T] (Func '1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess) \ r \ n in System. data. entity. core. objects. objectQuery '1. <> c _ DisplayClass7. <GetResults> B _ 5 () \ r \ n in System. data. entity. sqlServer. defaultSqlExecutionStrategy. execute [TResult] (Func '1 operation) \ r \ n in System. data. entity. core. objects. objectQuery '1. getResults (Nullable '1 forMergeOption) \ r \ n in System. data. entity. core. objects. objectQuery '1. <System. collections. generic. IEnumerable <T>. getEnumerator> B _ 0 () \ r \ n in System. data. entity. internal. lazyEnumerator '1. moveNext () \ r \ n in System. collections. generic. list '1 .. ctor (IEnumerable '1 collection) \ r \ n in System. linq. enumerable. toList [TSource] (IEnumerable '1 source) \ r \ n in RoslynBugShow. program. main (String [] args) Location d: \ documents \ visual studio 2015 \ Projects \ RoslynBugShow \ Program. cs: Row 14 "TargetSite: {System. data. entity. core. metadata. edm. typeUsage ValidateAndAdjustCastTypes (System. data. entity. core. metadata. edm. typeUsage, System. data. entity. core. metadata. edm. typeUsage, System. type, System. type)
BUG Analysis
When you see this, it is estimated that you can understand it. The code looks really okay. Why is there a problem? What is the more force conversions.
Anyway, I am entangled in vomiting blood here and thought it was a matter of entity design (in actual projects, entity design is of course much more complicated than above, troubleshooting is much more difficult). Later, I accidentally checked the decompilation code to find out the culprit. Next I will compare the compilation of the Unlocked Extension Method on the two compilers of VS2015 Update1 and VS2015:
Native VS2015 Compilation
VS2015 Update1 Compilation
From the decompilation code above, we can see that the compilation result of VS2015 Update1 has a forced conversion, but this forced conversion is not supported in the Linq To Entities, so it is reported
You cannot forcibly convert the type "RoslynBugShow. TestModel" to the type "RoslynBugShow. ILockable ". LINQ to Entities only supports forced conversion of EDM elements or enumeration types.
This exception.
The problem has risen to the compiler level, which is not solved by our civilian code farm. We can only expect Microsoft to solve it in the next update of VS2015.
Solution
Indeed, there are many cattle in the garden, and @ Choo on the 29 th floor provides a perfect solution to this problem.
ClassRestrictions: VS2015 Update1 and VS2015 compilation results are exactly the same, and the problem is solved successfully!
DEMO code download: RoslynBugShow.rar