I have some simple models in EF Core (with a Postgres backend using Npgsql).
public class Test : Model
{
public string Id { get; set; }
public TestInfo Info { get; set; }
public string Name { get; set; }
}
public class TestInfo
{
public string[] Tags { get; set; }
public string Name { get; set; }
public int[] Counts { get; set; }
}
public class TestDTO
{
public string[] Tags { get; set; }
public string Name { get; set; }
public string InfoName{ get; set; }
public int[] Counts { get; set; }
}
The EF Core config and Autommaper profile are
public class TestConfig
{
public override void Configure(EntityTypeBuilder<Test> builder)
{
builder.HasKey(m => m.Id);
builder.Property(s => s.Info)
.HasConversion(
v => JsonConvert.SerializeObject(v),
v => JsonConvert.DeserializeObject<TestInfo>(v)
)
.HasColumnType("jsonb");
builder.HasIndex(s => s.Info)
.HasMethod("gin")
.HasOperators("jsonb_ops");
}
}
public class TestProfile : Profile
{
public TestProfile()
{
CreateMap<Test, TestDTO>()
.ForMember(dest => dest.InfoName, opt => opt.MapFrom(src => src.Info.Name))
.ForMember(dest => dest.Tags, opt => opt.MapFrom(src => src.Info.Tags))
.ForMember(dest => dest.Counts, opt => opt.MapFrom(src => src.Info.Counts))
.ReverseMap();
}
}
I have been trying to use Automapper's ProjectTo to query but unable to figure out how to make it work. The below controller code throws coercion errors
[HttpGet]
[Route("/test/{id}")]
public async Task<IActionResult> GetTest([FromRoute (Name = "id")][Required]string id)
{
var t = await _mapper.ProjectTo<TestDTO>(
_context.Tests.Where(s => s.Id == id)
)
.ToListAsync();
return Ok(t);
}
Errors (there is another error from System.String to System.string[] for Tags but I left out for brevity)
System.InvalidOperationException: No coercion operator is defined between types 'System.String' and 'System.Int32[]'.
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 System.Linq.Expressions.Expression.Convert(Expression expression, Type type)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.CreateGetValueExpression(ParameterExpression dbDataReader, Int32 index, Boolean nullable, RelationalTypeMapping typeMapping, Type type, IPropertyBase property)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitExtension(Expression extensionExpression)
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberAssignment(MemberAssignment node)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node)
at System.Linq.Expressions.ExpressionVisitor.Visit[T](ReadOnlyCollection`1 nodes, Func`2 elementVisitor)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberInit(MemberInitExpression node)
at System.Linq.Expressions.MemberInitExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.ProcessShaper(Expression shaperExpression, RelationalCommandCache& relationalCommandCache, LambdaExpression& relatedDataLoaders)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.VisitShapedQuery(ShapedQueryExpression shapedQueryExpression)
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.VisitExtension(Expression extensionExpression)
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass12_0`1.<ExecuteAsync>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)
at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.GetAsyncEnumerator()
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at dms_apis.Controllers.OrganisationController.GetTest(String id) in /home/viet/src/dms-apis/Controllers/OrganisationController.cs:line 62
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
I tried manual mapping using Select in the controller and that appears to work but ProjectTo seems to be much nicer
[HttpGet]
[Route("/test/{id}")]
public async Task<IActionResult> GetTest([FromRoute (Name = "id")][Required]string id)
{
var t = _context.Tests
.Select(s => new TestDTO{
Id = s.Id,
Name = s.Info.Name
})
.Where(s => s.Id == id)
.ToList();
return Ok(t);
}
What is the correct way to use ProjectTo in this case? Thanks a lot.
Related
I have an gRPC application with EF core as ORM. AutoMapper's ProjectTo method is used to construct DTOs. But I get error when constructing collection properties. I prepared the following example:
Database entities:
public sealed class Horse
{
public Guid Id { get; init; }
public ICollection<Workout> Workouts { get; } = new HashSet<Workout>();
}
public sealed class Workout
{
public Guid Id { get; init; }
}
Context:
public sealed class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) { }
public DbSet<Horse> Horse { get; private init; } = null!;
}
DTOs:
public sealed class HorseDto
{
public Guid Id { get; init; }
public RepeatedField<WorkoutDto> Workouts { get; init; } = new RepeatedField<WorkoutDto>();
}
public sealed class WorkoutDto
{
public Guid Id { get; init; }
}
Mapping:
var mapperConfiguration =
new MapperConfiguration(_ =>
{
_.CreateMap<Horse, HorseDto>();
_.CreateMap<Workout, WorkoutDto>();
});
When I do:
var horseDto = await context.Horse
.Where(_ => _.Workouts.Count > 0)
.ProjectTo<HorseDto>(mapperConfiguration)
.FirstAsync();
I get:
System.ArgumentException: Argument types do not match
at System.Linq.Expressions.Expression.Bind(MemberInfo member, Expression expression)
at AutoMapper.QueryableExtensions.Impl.EnumerableExpressionBinder.BindEnumerableExpression(IConfigurationProvider configuration, PropertyMap propertyMap, ExpressionRequest request, ExpressionResolutionResult result, IDictionary`2 typePairCount, LetPropertyMaps letPropertyMaps)
at AutoMapper.QueryableExtensions.Impl.EnumerableExpressionBinder.Build(IConfigurationProvider configuration, PropertyMap propertyMap, TypeMap propertyTypeMap, ExpressionRequest request, ExpressionResolutionResult result, IDictionary`2 typePairCount, LetPropertyMaps letPropertyMaps)
at AutoMapper.QueryableExtensions.ExpressionBuilder.<>c__DisplayClass10_0.<CreateMapExpressionCore>g__CreateMemberBinding|4(PropertyExpression propertyExpression, <>c__DisplayClass10_1& )
at AutoMapper.QueryableExtensions.ExpressionBuilder.<>c__DisplayClass10_0.<CreateMapExpressionCore>g__CreateMemberBindings|1()
at AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpressionCore(ExpressionRequest request, Expression instanceParameter, IDictionary`2 typePairCount, TypeMap typeMap, LetPropertyMaps letPropertyMaps)
at AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpressionCore(ExpressionRequest request, Expression instanceParameter, IDictionary`2 typePairCount, LetPropertyMaps letPropertyMaps, TypeMap& typeMap)
at AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpression(ExpressionRequest request, IDictionary`2 typePairCount, LetPropertyMaps letPropertyMaps)
at AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpression(ExpressionRequest request)
at AutoMapper.Internal.LockingConcurrentDictionary`2.<>c__DisplayClass2_1.<.ctor>b__1()
at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
at System.Lazy`1.CreateValue()
at System.Lazy`1.get_Value()
at AutoMapper.Internal.LockingConcurrentDictionary`2.GetOrAdd(TKey key)
at AutoMapper.QueryableExtensions.ExpressionBuilder.GetMapExpression(Type sourceType, Type destinationType, Object parameters, MemberInfo[] membersToExpand)
at AutoMapper.QueryableExtensions.ProjectionExpression.ToCore(Type destinationType, Object parameters, IEnumerable`1 memberPathsToExpand)
at AutoMapper.QueryableExtensions.ProjectionExpression.ToCore[TResult](Object parameters, IEnumerable`1 memberPathsToExpand)
at AutoMapper.QueryableExtensions.ProjectionExpression.To[TResult](Object parameters, Expression`1[] membersToExpand)
at AutoMapper.QueryableExtensions.Extensions.ProjectTo[TDestination](IQueryable source, IConfigurationProvider configuration, Object parameters, Expression`1[] membersToExpand)
at AutoMapper.QueryableExtensions.Extensions.ProjectTo[TDestination](IQueryable source, IConfigurationProvider configuration, Expression`1[] membersToExpand)
at RepeatedFieldExample.Sandbox.Run()
Everything works fine if I replace RepeatedField<> with IEnumerable<>.
Workable direct LINQ Select:
var horseDto = await ctx.Horse
.Where(h => h.Workouts.Count > 0)
.Select(h => new HorseDto()
{
Id = h.Id,
Workouts = new RepeatedField<WorkoutDto>()
{
h.Workouts.Select(w => new WorkoutDto() {Id = w.Id})
}
})
.FirstAsync();
AutoMapper version is 10.1.1
I'm getting the following error trying to load the results of my Postgres function into a EF entity.
Error:
Microsoft.EntityFrameworkCore.Query: Error: An exception occurred while iterating over the results of a query for context type 'Rainman.Data.RainmanDbContext'.
System.Threading.ThreadAbortException: System error.
at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior, Boolean async, CancellationToken cancellationToken)
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior, Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior)
at Npgsql.NpgsqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
at System.Data.Common.DbCommand.ExecuteReader()
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
at Microsoft.EntityFrameworkCore.Query.Internal.FromSqlQueryingEnumerable`1.Enumerator.InitializeReader(DbContext _, Boolean result)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
at Microsoft.EntityFrameworkCore.Query.Internal.FromSqlQueryingEnumerable`1.Enumerator.MoveNext()
While running the following code:
FormattableString query = $"SELECT sortedsetkey as \"SortedSetKey\", keyorder as \"KeyOrder\", value as \"Value\" FROM public.fn_test_lcr_custom({routePlan.DeckApplyCustomer.tg_id}, {routePlan.effective_date});";
Console.WriteLine($"\n\nQUERY:\n{query}\n\n");
IEnumerable <CustomerRoutingCache> tmpList = RainmanDbContext.CustomerRoutingCaches.FromSqlInterpolated(query).AsEnumerable();
This SQL Function Definition for the function being called on the Postgres side (ver 13):
CREATE OR REPLACE FUNCTION public.fn_test_lcr_custom(
p_tg_id text,
p_as_of_date timestamp with time zone)
RETURNS TABLE(SortedSetKey text, KeyOrder int, Value text)
The class that it being translated into is:
public class CustomerRoutingCache
{
[Key]
public string SortedSetKey { get; set; }
public int KeyOrder { get; set; }
public string Value { get; set; }
}
Using .net core 5, npgsql
I was just trying some features of entity framework 5 and kendo ui. I have a following ProductType enum
public enum ProductType {
[Description("Hazardous")]
Hazardous,
[Description("Non Hazardous")]
NonHazardous
}
This enum type is one of the field in the Product Entity.
[Table("Products")]
public class Product {
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
//Other Fields ...
[Required(ErrorMessage="Product Type is Required")]
public ProductType ProductType {get;set;}
}
The ProductType column in the underlying SQL Server Database is defined as (tinyint, not null).
I access list of Products in the following Controller Action of MVC
public ActionResult _ProductList(int pageSize, int skip) {
using (WorkUnit workUnit = new WorkUnit()) {
IQueryable<Product> products = workUnit.ProductRepository.GetAllProducts()
.Include(p => p.Category);
int total = products.Count();
List<Product> productList = products.ToList<Product>(); //Throws InvalidOperationException
return Json(new { total = total, data = productList }, JsonRequestBehavior.AllowGet);
}
}
Here is the description of the InvalidOperationException that is thrown on products.ToList() in the above controller action.
The 'ProductType' property on 'Product' could not be set to a 'Byte' value.
You must set this property to a non-null value of type 'ProductType'.
Any guesses why ToList() is throwing an InvalidOperationException.
Just for info, the Database existed previously, and the Entities were manually coded based on the Database as POCO's.
Edit
Here is the complete exception details
System.InvalidOperationException was unhandled by user code
HResult=-2146233079
Message=The 'ProductType' property on 'Product' could not be set to a 'Byte' value. You must set this property to a non-null value of type 'ProductType'.
Source=System.Data.Entity
StackTrace:
at System.Data.Common.Internal.Materialization.Shaper.ErrorHandlingValueReader`1.GetValue(DbDataReader reader, Int32 ordinal)
at System.Data.Common.Internal.Materialization.Shaper.GetPropertyValueWithErrorHandling[TProperty](Int32 ordinal, String propertyName, String typeName)
at lambda_method(Closure , Shaper )
at System.Data.Common.Internal.Materialization.Shaper.HandleEntityAppendOnly[TEntity](Func`2 constructEntityDelegate, EntityKey entityKey, EntitySet entitySet)
at lambda_method(Closure , Shaper )
at System.Data.Common.Internal.Materialization.Coordinator`1.ReadNextElement(Shaper shaper)
at System.Data.Common.Internal.Materialization.Shaper`1.SimpleEnumerator.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at KendoUI_Web_Demo.Controllers.HomeController._ProductList(Int32 pageSize, Int32 skip) in d:\Practice\ASP.NET_MVC\KendoUI_Web_Demo\KendoUI_Web_Demo\Controllers\HomeController.cs:line 52
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass42.<BeginInvokeSynchronousActionMethod>b__41()
at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass37.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49()
InnerException:
There is a mismatch between the enum type which in your case is int based and your database where the column is byte (tinyint) based. You can fix this by setting the correct underlying type of your enum type:
public enum ProductType : byte
{
...
}
I've just switched our project to try Entity Framework 5.0 RC, running under .NET 4.0. Aside from updating namespace references, we haven't made any code changes. I'm getting the following the first time we try to access an entity framework object:
at System.Data.Entity.ModelConfiguration.Conventions.ForeignKeyNavigationPropertyAttributeConvention.System.Data.Entity.ModelConfiguration.Conventions.IEdmConvention<System.Data.Entity.Edm.EdmNavigationProperty>.Apply(EdmNavigationProperty navigationProperty, EdmModel model)
at System.Data.Entity.ModelConfiguration.Configuration.ConventionsConfiguration.EdmConventionDispatcher.Dispatch[TEdmDataModelItem](TEdmDataModelItem item)
at System.Data.Entity.ModelConfiguration.Configuration.ConventionsConfiguration.EdmConventionDispatcher.VisitEdmNavigationProperty(EdmNavigationProperty item)
at System.Data.Entity.Edm.Internal.DataModelItemVisitor.VisitCollection[T](IEnumerable`1 collection, Action`1 visitMethod)
at System.Data.Entity.Edm.Internal.EdmModelVisitor.VisitDeclaredNavigationProperties(EdmEntityType entityType, IEnumerable`1 navigationProperties)
at System.Data.Entity.ModelConfiguration.Configuration.ConventionsConfiguration.EdmConventionDispatcher.VisitEdmEntityType(EdmEntityType item)
at System.Data.Entity.Edm.Internal.DataModelItemVisitor.VisitCollection[T](IEnumerable`1 collection, Action`1 visitMethod)
at System.Data.Entity.Edm.Internal.EdmModelVisitor.VisitEntityTypes(EdmNamespace edmNamespace, IEnumerable`1 entityTypes)
at System.Data.Entity.Edm.Internal.EdmModelVisitor.VisitEdmNamespace(EdmNamespace item)
at System.Data.Entity.ModelConfiguration.Configuration.ConventionsConfiguration.EdmConventionDispatcher.VisitEdmNamespace(EdmNamespace item)
at System.Data.Entity.Edm.Internal.DataModelItemVisitor.VisitCollection[T](IEnumerable`1 collection, Action`1 visitMethod)
at System.Data.Entity.Edm.Internal.EdmModelVisitor.VisitNamespaces(EdmModel model, IEnumerable`1 namespaces)
at System.Data.Entity.Edm.Internal.EdmModelVisitor.VisitEdmModel(EdmModel item)
at System.Data.Entity.ModelConfiguration.Configuration.ConventionsConfiguration.EdmConventionDispatcher.VisitEdmModel(EdmModel item)
at System.Data.Entity.ModelConfiguration.Configuration.ConventionsConfiguration.EdmConventionDispatcher.Dispatch()
at System.Data.Entity.ModelConfiguration.Configuration.ConventionsConfiguration.ApplyModel(EdmModel model)
at System.Data.Entity.DbModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo)
at System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)
at System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext)
at System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input)
at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
at System.Data.Entity.Internal.InternalContext.Initialize()
at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
at System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext()
at System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider()
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)
at BackEnd.Facade.Implementations.UserService.GetUserByUserName(String userName) in c:\Development\FundApps\Rapptr\src\FundApps.Rapptr.ServiceLayer\Facade\Implementations\UserService.cs:line 61
at FundApps.Rapptr.Common.Web.Security.WebUserContextModule.OnPostAuthenticateRequest(HttpContextBase context) in c:\Development\FundApps\Rapptr\src\FundApps.Rapptr.Common.Web\Security\WebUserContextModule.cs:line 54
at FundApps.Common.Mvc.BaseHttpModule.<Init>b__1(Object sender, EventArgs e) in c:\Development\FundApps\Rapptr\src\FundApps.Common.Mvc\BaseHttpModule.cs:line 14
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
Does anyone have any suggestions as to what might cause this and how to narrow it down?
UPDATE: This bug was fixed in EF5 RTM.
This is a bug in EF5. It happens when you have a 1:1 relationship and also use the ForeignKey attribute to explicitly specify the FK. For example:
public class OneToOneResult
{
public int OneToOneResultId { get; set; }
[ForeignKey("OneToOneResultId")]
public virtual OneToOneResultDetail Detail { get; set; }
}
public class OneToOneResultDetail
{
[Key]
public int OneToOneResultId { get; set; }
public DateTime DataDate { get; set; }
}
In OnModelCreating:
modelBuilder.Entity<OneToOneResult>()
.HasRequired(r => r.Detail)
.WithRequiredPrincipal();
The workaround is to remove the ForeignKey attribute. It is not needed in this case because the 1:1 relationship must be PK to PK since that is all that EF supports in this case.
Given the following model:
public class Foo
{
public int Id { get; set;}
public Bar TheBar { get; set; }
}
public class Bar
{
public int Id { get; set;}
}
EF tries to generate the FK column as BarId.
How can make it use TheBar?
I've tried the following:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Foo>()
.HasOptional(x => x.Bar)
.WithMany()
.IsIndependent()
.Map(x => x.MapKey(bar => bar.Id, "TheBar"));
}
But I get the following exception when trying to use the context:
Exception has been thrown by the target of an invocation.
---> System.InvalidOperationException: Sequence contains more than one matching element
Server stack trace:
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
at System.Data.Entity.ModelConfiguration.Configuration.Properties.Navigation.IndependentAssociationMappingConfiguration`1.Configure(DbAssociationSetMapping associationSetMapping)
at System.Data.Entity.ModelConfiguration.Configuration.Properties.Navigation.NavigationPropertyConfiguration.Configure(DbDatabaseMapping databaseMapping)
at System.Data.Entity.ModelConfiguration.Utilities.IEnumerableExtensions.Each[T](IEnumerable`1 ts, Action`1 action)
at System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.ConfigureAssociationMappings(DbDatabaseMapping databaseMapping)
at System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.Configure(DbEntityTypeMapping entityTypeMapping, DbDatabaseMapping databaseMapping, DbProviderManifest providerManifest)
at System.Data.Entity.ModelConfiguration.Configuration.ModelConfiguration.Configure(DbDatabaseMapping databaseMapping, DbProviderManifest providerManifest)
at System.Data.Entity.ModelConfiguration.ModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo, Boolean validateModel)
at System.Data.Entity.ModelConfiguration.ModelBuilder.Build(DbConnection providerConnection)
at System.Data.Entity.Internal.LazyInternalContext.CreateModel()
at System.Lazy`1.CreateValue()
Exception rethrown at [0]:
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
at System.Data.Entity.ModelConfiguration.Configuration.Properties.Navigation.IndependentAssociationMappingConfiguration`1.Configure(DbAssociationSetMapping associationSetMapping)
at System.Data.Entity.ModelConfiguration.Configuration.Properties.Navigation.NavigationPropertyConfiguration.Configure(DbDatabaseMapping databaseMapping)
at System.Data.Entity.ModelConfiguration.Utilities.IEnumerableExtensions.Each[T](IEnumerable`1 ts, Action`1 action)
at System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.ConfigureAssociationMappings(DbDatabaseMapping databaseMapping)
at System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.Configure(DbEntityTypeMapping entityTypeMapping, DbDatabaseMapping databaseMapping, DbProviderManifest providerManifest)
at System.Data.Entity.ModelConfiguration.Configuration.ModelConfiguration.Configure(DbDatabaseMapping databaseMapping, DbProviderManifest providerManifest)
at System.Data.Entity.ModelConfiguration.ModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo, Boolean validateModel)
at System.Data.Entity.ModelConfiguration.ModelBuilder.Build(DbConnection providerConnection)
at System.Data.Entity.Internal.LazyInternalContext.CreateModel()
at System.Lazy`1.CreateValue()
at System.Lazy`1.LazyInitValue()
at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
at System.Data.Entity.Internal.Linq.InternalSet`1.get_Provider()
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
The error was caused by a bug in CTP5. If the Id property was defined in a base class (which is not shown in the code above because I didn't think it was related), it breaks.
I solved it by defining a base interface, but keeping the Id in each class.
You want the MapKey method in the fluent interface.
Alternately, if you do this throughout your model, CTP 5 has pluggable conventions, although this is, AFAIK, not well-documented yet.