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

Explicitly set constructor binding should stop convention from running #13891

Closed
smitpatel opened this issue Nov 5, 2018 · 3 comments · Fixed by #16486
Closed

Explicitly set constructor binding should stop convention from running #13891

smitpatel opened this issue Nov 5, 2018 · 3 comments · Fixed by #16486
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported type-bug
Milestone

Comments

@smitpatel
Copy link
Contributor

    public class Project
    {
        public Project(string name, int anotherProp)
        {
            Name = name;
            AnotherProp = anotherProp;
        }

        public Project(string name, string lastname)
        {
            Name = name;
            Lastname = lastname;
        }

        public Project(string name, string lastname, int anotherProp)
            : this(name, lastname)
        {
            AnotherProp = anotherProp;
        }

        public Guid Id { get; set; }
        public string Name { get; set; }
        public string Lastname { get; set; }
        public int AnotherProp { get; set;  }
    }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // Configure model
            modelBuilder.Entity<Project>(e =>
            {
                e.Property(p => p.Name).UsePropertyAccessMode(PropertyAccessMode.FieldDuringConstruction);
                e.Property(p => p.AnotherProp).UsePropertyAccessMode(PropertyAccessMode.FieldDuringConstruction);
                e.Property(p => p.Lastname).UsePropertyAccessMode(PropertyAccessMode.FieldDuringConstruction);
            });
        }
Unhandled Exception: System.InvalidOperationException: Two constructors were found with the same number of parameters that could both be used by Entity Framework. The constructor to use must be configured explicitly. The two constructors are 'Project(string, int)' and 'Project(string, string)'.
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConstructorBindingConvention.Apply(InternalModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelBuilt(InternalModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
   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.Internal.InternalAccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.get_DatabaseCreator()
   at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.EnsureDeleted()
   at EFSampleApp.Program.Main(String[] args) in D:\code\EFSampleApp\EFSampleApp\Program.cs:line 15

EF Core version: 2.2.0-rtm-35637

@ajcvickers
Copy link
Contributor

This is currently by-design per: #10852, but also see #10865.

The constructor binding can be set explicitly using internal code.

Warning: internal code should be used with caution, since it may be changed or removed in a breaking way in any new release.

modelBuilder.Entity<Project>(e =>
{
    var nameProperty = e.Property(p => p.Name).Metadata;
    var anotherProperty = e.Property(p => p.AnotherProp).Metadata;
    var lastNameProperty = e.Property(p => p.Lastname).Metadata;

    e.Metadata[CoreAnnotationNames.ConstructorBinding]
        = new DirectConstructorBinding(
            typeof(Project).GetConstructor(new [] { typeof(string), typeof(string), typeof(int) }),
            new []
            {
                new PropertyParameterBinding(nameProperty),
                new PropertyParameterBinding(lastNameProperty),
                new PropertyParameterBinding(anotherProperty),
            });
});

However, I found while working on this that the convention still runs and throws even though its result would not be used--this is a bug. I was able to workaround this by adding a private parameterless constrctor to the entity type:

public class Project
{
    private Project()
    {
    }

    ...
}

This allows the convention to succeed, with the result being that the explicitly configured constructor is used.

@ajcvickers ajcvickers changed the title Constructor binding fails to find ctor with largest number of matching parameters Explicitly set constructor binding should stop convention from running Nov 5, 2018
@ajcvickers ajcvickers self-assigned this Nov 5, 2018
@ajcvickers ajcvickers added this to the 3.0.0 milestone Nov 5, 2018
@ahedreville
Copy link

Hi All
There is any update about when this bug will be fixed?
Thanks a lot in advance.

@ajcvickers
Copy link
Contributor

ajcvickers commented Mar 20, 2019

@ahedreville Currently planned for the 3.0 release; that's why the issue is in the "3.0.0" milestone.

@ajcvickers ajcvickers added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Jul 6, 2019
@ajcvickers ajcvickers modified the milestones: 3.0.0, 3.0.0-preview8 Jul 29, 2019
@ajcvickers ajcvickers modified the milestones: 3.0.0-preview8, 3.0.0 Nov 11, 2019
@ajcvickers ajcvickers removed their assignment Sep 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported type-bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants