Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error when we use owned type as a alternate key. #13566

Closed
lurumad opened this issue Oct 10, 2018 · 5 comments
Closed

Error when we use owned type as a alternate key. #13566

lurumad opened this issue Oct 10, 2018 · 5 comments

Comments

@lurumad
Copy link

lurumad commented Oct 10, 2018

Hi folks,

Given the next model:

public class Product : AggregateRoot, IAuditable
{
    public NaturalNumber ProductNumber { get; private set; }
    internal int ProductTypeId { get; private set; }
    internal ProductType ProductType { get; private set; }

...

public class NaturalNumber : ValueObject
{
    internal int value;

    private NaturalNumber(){ }

    private NaturalNumber(int value)
    {
        Ensure.That<DomainException>(value >= 0, "Invalid natural number. {value} should be bigger than zero.");
        this.value = value;
    }

    public static NaturalNumber New(int value)
    {
        return new NaturalNumber(value);
    }

    public static implicit operator int(NaturalNumber number)
    {
        return number.value;
    }

    public static explicit operator NaturalNumber(int value)
    {
        return new NaturalNumber(value);
    }

    protected override IEnumerable<object> GetAtomicValues()
    {
        yield return value;
    }
}

ProductNumber and ProductTypeId need to be alternate key, so if a try to configure like this:

builder.HasAlternateKey(p => new { p.ProductTypeId, p.ProductNumber.value });

We received this error:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentException: The properties expression 'p => new <>f__AnonymousType12`2(ProductTypeId = p.ProductTypeId, value = p.ProductNumber.value)' is not valid. The expression should represent a simple property access: 't => t.MyProperty'. When specifying multiple properties use an anonymous type: 't => new { t.MyProperty1, t.MyProperty2 }'.
Parameter name: propertyAccessExpression
   at Microsoft.EntityFrameworkCore.Internal.ExpressionExtensions.GetPropertyAccessList(LambdaExpression propertyAccessExpression)
   at Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder`1.HasAlternateKey(Expression`1 keyExpression)
   at xxx.Schedule.Infrastructure.EntityConfiguration.ProductEntityConfiguration.Configure(EntityTypeBuilder`1 builder) in C:\Dev\xxxx\src\Schedule\xxxx.Schedule.Infrastructure\EntityConfiguration\ProductEntityConfiguration.cs:line 13
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at Microsoft.EntityFrameworkCore.ModelBuilderExtensions.ApplyConfigurationsFromAssembly(ModelBuilder modelBuilder, Assembly assembly) in C:\Dev\xxx\src\Schedule\xxx.Schedule.Infrastructure\Extensions\ModelBuilderExtensions.cs:line 111
   at xxx.Schedule.Infrastructure.ScheduleDbContext.OnModelCreating(ModelBuilder modelBuilder) in C:\Dev\xxxx\src\Schedule\xxx.Schedule.Infrastructure\DataContext\ScheduleDbContext.cs:line 31
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelCustomizer.Customize(ModelBuilder modelBuilder, DbContext context)
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelCustomizer.Customize(ModelBuilder modelBuilder, DbContext context)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.<>c__DisplayClass5_0.<GetModel>b__1()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_1(IServiceProvider p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
   at Microsoft.EntityFrameworkCore.Internal.InternalAccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func`1 factory)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_1.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Exception has been thrown by the target of an invocation.

Further technical details

EF Core version: 2.1.1
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
Operating system: Windows 10 Enterprise 1803
IDE: Microsoft Visual Studio Enterprise 2017
Version 15.8.5
VisualStudio.15.Release/15.8.5+28010.2036
Microsoft .NET Framework
Version 4.7.03056

Any ideas?

@ajcvickers
Copy link
Contributor

ajcvickers commented Oct 10, 2018

@lurumad Can you give some details on why the alternate key is needed? The issue is similar to #11336, except that is just about creating indexes, not full EF alternate keys, which have more semantics.

@lurumad
Copy link
Author

lurumad commented Oct 15, 2018

Hi @ajcvickers

Of course, I can explain you. We have our own Id, but these two properties need be unique, because they are the compose key of legacy software that we need to integrate with our app and of course, we need to use Find to retrieve the products by this key because the legacy system it doesn't know our Id and send us the compose key.

Regards!

@ajcvickers
Copy link
Contributor

@lurumad Given that Find doesn't work with alternate keys, does this change? Do you really need this to be the primary key?

@lurumad
Copy link
Author

lurumad commented Oct 17, 2018

Hi @ajcvickers

Ok, we can find using a LINQ expresion without using Find but we need to make unique { p.ProductTypeId, p.ProductNumber.value } Is that possible?

Regards!

@ajcvickers
Copy link
Contributor

@lurumad That is being tracked by #11336, so closing this as a duplicate of that.

@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants