This project has moved and is read-only. For the latest updates, please go here.

Differences in query compilation between real DbContext and Effort DbContext

Jun 18, 2014 at 4:25 PM
I'm using Entity Framework 6.1 with the Effort.EF6 NuGet package and I assumed that LINQ query run using Effort would pass through the exact same pipeline as they would when connecting to the database, but that doesn't seem the case. I'm seeing my unit test (with Effort) fail, while the query runs fine when I run the application.

I've got the following LINQ query:
var results =
    from record in this.db.MaintenanceHistory
    where record.Asset.Id == query.AssetId
    orderby record.Date
    select new
    {
        Dealer = record.Dealer,
        Usage = record.Usage + " (" + record.UsageUnit + ")",
        Code = record.Code,
        Description = record.Description,
    };
Here record.Usage is an Nullable<int> and record.UsageUnit is a string. When I run this to query the database, but when I intercept this with Effort I get the following exception:
No coercion operator is defined between types 'System.Nullable`1[System.Int32]' and 'System.String'.
I use the following code to hook up Effort:
var builder = new EntityConnectionStringBuilder();

builder.Metadata = 
    "res://*/DataModel.AssetsDataModel.csdl|" +
    "res://*/DataModel.AssetsDataModel.ssdl|" +
    "res://*/DataModel.AssetsDataModel.msl";
builder.Provider = "System.Data.SqlClient";
builder.ProviderConnectionString = "fake connection string";

string entityConnectionString = builder.ToString();

DbConnection connection = EntityConnectionFactory.CreateTransient(entityConnectionString);

return new AssetsEntities(connection, contextOwnsConnection: true);
If however I change the previous query to the following, my unit test (with Effort) succeeds:
var results =
    from record in this.db.MaintenanceHistory
    where record.Asset.Id == query.AssetId
    orderby record.Date
    select new
    {
        Dealer = record.Dealer,
        Usage = record.Usage,
        Code = record.Code,
        Description = record.Description,
    };
This makes me conclude that there might still be differences between how Effort does things and how Entity Framework does things.

Is there a way to make Effort behave more like the real Entity Framework?


btw here's the complete stack trace:
System.Data.Entity.Core.EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details. ---> System.InvalidOperationException: No coercion operator is defined between types 'System.Nullable`1[System.Int32]' and 'System.String'.
Result StackTrace:  
at System.Linq.Expressions.Expression.GetUserDefinedCoercionOrThrow(ExpressionType coercionType, Expression expression, Type convertToType)
   at System.Linq.Expressions.Expression.Convert(Expression expression, Type type, MethodInfo method)
   at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbCastExpression expression)
   at System.Data.Entity.Core.Common.CommandTrees.DbCastExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
   at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbExpression expression)
   at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbFunctionExpression expression)
   at System.Data.Entity.Core.Common.CommandTrees.DbFunctionExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
   at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbExpression expression)
   at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbFunctionExpression expression)
   at System.Data.Entity.Core.Common.CommandTrees.DbFunctionExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
   at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbExpression expression)
   at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbFunctionExpression expression)
   at System.Data.Entity.Core.Common.CommandTrees.DbFunctionExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
   at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbExpression expression)
   at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.VisitExpressions(IList`1 expressions)
   at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbNewInstanceExpression expression)
   at System.Data.Entity.Core.Common.CommandTrees.DbNewInstanceExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
   at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbExpression expression)
   at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbProjectExpression expression)
   at System.Data.Entity.Core.Common.CommandTrees.DbProjectExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
   at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbExpression expression)
   at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbSortExpression expression)
   at System.Data.Entity.Core.Common.CommandTrees.DbSortExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
   at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbExpression expression)
   at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbProjectExpression expression)
   at System.Data.Entity.Core.Common.CommandTrees.DbProjectExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
   at Effort.Internal.DbCommandTreeTransformation.TransformVisitor.Visit(DbExpression expression)
   at Effort.Internal.CommandActions.QueryCommandAction.ExecuteDataReader(ActionContext context)
   at Effort.Provider.EffortEntityCommand.ExecuteDbDataReader(CommandBehavior behavior)
   at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)
   at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<Reader>b__c(DbCommand t, DbCommandInterceptionContext`1 c)
   at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
   at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand command, DbCommandInterceptionContext interceptionContext)
   at System.Data.Entity.Internal.InterceptableDbCommand.ExecuteDbDataReader(CommandBehavior behavior)
   at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)
   at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)
 --- End of inner exception stack trace ---
    at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)
   at System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlan.Execute[TResultType](ObjectContext context, ObjectParameterCollection parameterValues)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__6()
   at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__5()
   at System.Data.Entity.Infrastructure.DefaultExecutionStrategy.Execute[TResult](Func`1 operation)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()
   at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at DLL.IRT.Backoffice.Assets.BusinessLayer.Queries.GetMaintenanceHistoryForAssetQueryHandler.Handle(GetMaintenanceHistoryForAssetQuery query) in c:\DLL\Source\Backoffice\DLL.IRT.Backoffice.Assets.BusinessLayer\Queries\GetMaintenanceHistoryForAssetQuery.cs:line 59
   at DLL.IRT.Backoffice.Assets.BusinessLayer.Tests.Queries.GetMaintenanceHistoryForAssetQueryHandlerTests.Handle_RunningTheQueryThroughTheEntityFrameworkPipeline_Succeeds() in c:\DLL\Source\Backoffice\DLL.IRT.Backoffice.Assets.BusinessLayer.Tests\Queries\GetMaintenanceHistoryForAssetQueryHandlerTests.cs:line 22
Jun 18, 2014 at 7:06 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Jun 18, 2014 at 8:13 PM
Thank you for takimg thr time to look into this and for creating an issue for this. Can you explain what Effort does under the covers that causes it to break while EF succeeds in executing that query? My understanding was that Effort would simply use the EF query pipeline and that this would ensure that all queries would be transformed the same way, but this understanding seems incorrect.

I'm currently ivestigating whether Effort would be a good tool in our development process, but indirectly failed on the first production query. Can you explain what risks are involved in using Effort? Do you need to keep Effort is sync constantly with new versions of EF or can LINQ queries that can be only executed with newer versions of EF automatically be executed with the current version of Effort?

Thanks in advance.
Jun 18, 2014 at 10:58 PM
Basically Effort is an in-memory Entity Framework provider. Features that require provider support will not automatically work, but this is the case with any other provider too. Your failure is probably caused by a bug in the DbCommandTree transformer.

I use Effort in a company project and it works well in wide range of scenarios, but it is always possible that it has not been prepared for a certain setup.