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

Allow related entities to be passed to constructor of aggregate root #12078

Open
Tracked by #240 ...
andriysavin opened this issue May 21, 2018 · 25 comments
Open
Tracked by #240 ...

Allow related entities to be passed to constructor of aggregate root #12078

andriysavin opened this issue May 21, 2018 · 25 comments

Comments

@andriysavin
Copy link

andriysavin commented May 21, 2018

Note--see comments for actual issue.

Original issue:
I'm trying constructor injection feature of EF Core 2.1 RC1. Consider the following entities and DBContext configuration:

 public class MyEntity
    {
        public int Id { get; set; }
        public OwnedEntity Owned1 { get; private set; }
        public OwnedEntity Owned2 { get; private set; }

        private MyEntity() { }

        public MyEntity(OwnedEntity oned1, OwnedEntity owned2)
        {
            Owned1 = oned1;
            Owned2 = owned2;
        }
    }

    public class OwnedEntity
    {
        public double MyProperty { get; }
        public OwnedEntity(double myProperty) => MyProperty = myProperty;
    }

 protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<OwnedEntity>(b =>
            {
                b.Property(e => e.MyProperty);
            });

            modelBuilder.Entity<MyEntity>(cb =>
            {
                cb.OwnsOne(seg => seg.Owned1);
                cb.OwnsOne(seg => seg.Owned2);
            });
        }

When I'm trying to add a new entity to the set, I'm getting the following exception:

Unhandled Exception: System.InvalidOperationException: No suitable constructor found for entity type 'MyEntity.Owned2#OwnedEntity'. The following parameters could not be bound to properties of the entity: 'myProperty'.
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConstructorBindingConvention.Apply(InternalModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelBuilt(InternalModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelBuilt(InternalModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.Validate()
   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.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.EntryWithoutDetectChanges[TEntity](TEntity entity)
   at Microsoft.EntityFrameworkCore.DbContext.SetEntityState[TEntity](TEntity entity, EntityState entityState)
   at Microsoft.EntityFrameworkCore.DbContext.Add[TEntity](TEntity entity)
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.Add(TEntity entity)
   at TestEfCtorInjectionWithOwnedTypes.Program.Main(String[] args) 

What is interesting is that if I remove Owned1 or Owned2 property and all references to it, all works fine, though they are identical from configuration point of view. So its essential for this issue that at least two owned properties are present.

Further technical details

EF Core version: 2.1.0-rc1-final
Database Provider: doesn't matter, but is reproducable with InMemory and SqlServer.
IDE: Visual Studio 2017 15.7

Link to the VS solution on OneDrive: https://1drv.ms/u/s!AuaAKPMkiTEAxqgGlJX81J_GvbwIGA

@ajcvickers
Copy link
Member

@andriysavin The issue here is that owned types cannot be configured using a call the top level .Entity method. This was supposed to throw in 2.1, but that change was accidentally reverted-see issue #9148.

To make your code work you instead need to configure the property mapping for the owned type in each of the places it is used. For example:

modelBuilder.Entity<MyEntity>(cb =>
{
    cb.OwnsOne(seg => seg.Owned1).Property(e => e.MyProperty);
    cb.OwnsOne(seg => seg.Owned2).Property(e => e.MyProperty);
});

@andriysavin
Copy link
Author

andriysavin commented May 23, 2018

@ajcvickers Thanks for explaining, that makes it work, though this configuration may look messy if you have many properties in the owned type - you will have to repeat the same configuration:

cb.OwnsOne(seg => seg.Owned1, b =>
                {
                    b.Property(e => e.MyProperty1);
                    b.Property(e => e.MyProperty2);
                    b.Property(e => e.MyProperty3);
                    b.Property(e => e.MyProperty4);
                });

cb.OwnsOne(seg => seg.Owned2, b =>
                {
                    b.Property(e => e.MyProperty1);
                    b.Property(e => e.MyProperty2);
                    b.Property(e => e.MyProperty3);
                    b.Property(e => e.MyProperty4);
                });

cb.OwnsOne(seg => seg.Owned3, b =>
                {
                    b.Property(e => e.MyProperty1);
                    b.Property(e => e.MyProperty2);
                    b.Property(e => e.MyProperty3);
                    b.Property(e => e.MyProperty4);
                });

This can be simplified by extracting to a separate method or local function, of course, but looks not very fluent:

void buildAction(ReferenceOwnershipBuilder<MyEntity, OwnedEntity> b)
                {
                    b.Property(e => e.MyProperty1);
                    b.Property(e => e.MyProperty2);
                    b.Property(e => e.MyProperty3);
                    b.Property(e => e.MyProperty4);
                }

                cb.OwnsOne(seg => seg.Owned1, buildAction);
                cb.OwnsOne(seg => seg.Owned2, buildAction);

@andriysavin
Copy link
Author

andriysavin commented May 23, 2018

However, it's not all from me :)
I want constructor injection in MyEntity as well, so I commented out the parameterless constructor (see code below). And now I'm getting:

System.InvalidOperationException: No suitable constructor found for entity type 'MyEntity'. The following parameters could not be bound to properties of the entity: 'owned1', 'owned2'.

I can guess that this is due to (from the docs):

EF Core cannot set navigation properties (such as Blog or Posts above) using a constructor.

What's the reason for this limitation for owned types? If I have nested owned types, does that mean that only innermost owned type will be able to use constructor injection?

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

namespace TestEfCtorInjectionWithOwnedTypes
{
    public class MyEntity
    {
        public int Id { get; set; }
        public OwnedEntity Owned1 { get; private set; }
        public OwnedEntity Owned2 { get; private set; }

        //private MyEntity() { }

        public MyEntity(OwnedEntity owned1, OwnedEntity owned2)
        {
            Owned1 = owned1;
            Owned2 = owned2;
        }
    }

    public class OwnedEntity
    {
        public double MyProperty { get; }
        public OwnedEntity(double myProperty) => MyProperty = myProperty;
    }

    class MyDbContext : DbContext
    {
        public MyDbContext(DbContextOptions options) : base(options) { }

        public DbSet<MyEntity> MyEntities { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<MyEntity>(cb =>
            {
                cb.OwnsOne(seg => seg.Owned1).Property(e => e.MyProperty);
                cb.OwnsOne(seg => seg.Owned2).Property(e => e.MyProperty);
            });
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var services = new ServiceCollection();

            services.AddDbContext<MyDbContext>(options =>
                options.UseInMemoryDatabase("MyDatabase"));

            using (var sp = services.BuildServiceProvider())
            {
                var dbContext = sp.GetRequiredService<MyDbContext>();

                dbContext.MyEntities.Add(
                    new MyEntity(
                        new OwnedEntity(42),
                        new OwnedEntity(24)));
            }
        }
    }
}

@andriysavin
Copy link
Author

Here is an example with nested entities which doesn't work as well with error
System.InvalidOperationException: No suitable constructor found for entity type 'OwnedEntity'. The following parameters could not be bound to properties of the entity: 'ownedOwnedProperty'.

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

namespace TestEfCtorInjectionWithOwnedTypes
{
    public class MyEntity
    {
        public int Id { get; set; }
        public OwnedEntity Owned { get; private set; }
        private MyEntity() { }
        public MyEntity(OwnedEntity owned) => Owned = owned;
    }

    public class OwnedEntity
    {
        public OwnedOwnedEntity OwnedOwnedProperty { get; }
        public OwnedEntity(OwnedOwnedEntity ownedOwnedProperty)
            => OwnedOwnedProperty = ownedOwnedProperty;
    }

    public class OwnedOwnedEntity
    {
        public double MyProperty { get; }
        public OwnedOwnedEntity(double myProperty) => MyProperty = myProperty;
    }

    class MyDbContext : DbContext
    {
        public MyDbContext(DbContextOptions options) : base(options) { }

        public DbSet<MyEntity> MyEntities { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<MyEntity>(cb =>
            {
                cb.OwnsOne(seg => seg.Owned, b =>
                {
                    b.OwnsOne(e => e.OwnedOwnedProperty).Property(e => e.MyProperty);
                });
            });
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var services = new ServiceCollection();

            services.AddDbContext<MyDbContext>(options =>
                options.UseInMemoryDatabase("MyDatabase"));

            using (var sp = services.BuildServiceProvider())
            {
                var dbContext = sp.GetRequiredService<MyDbContext>();

                dbContext.MyEntities.Add(
                    new MyEntity(new OwnedEntity(new OwnedOwnedEntity(4242))));
            }
        }
    }
}

@ajcvickers
Copy link
Member

Re-opening to discuss in triage.

@ajcvickers ajcvickers reopened this May 23, 2018
@ajcvickers ajcvickers changed the title No suitable constructor found for entity type 'MyEntity.Owned2#OwnedEntity' Allow related entities to be passed to constructor of aggregate root May 24, 2018
@ajcvickers ajcvickers added this to the Backlog milestone May 24, 2018
@ajcvickers
Copy link
Member

Triage: moving this to the backlog as a feature request to pass related entity instances to the constructor of a parent instance, which is most useful for aggregates. See also #1985

@andriysavin
Copy link
Author

andriysavin commented May 26, 2018

Just to give a more real life example, here are some of my models (simplified).
To be accurate, this is how I want them to look like: GeoPosition and GeoSegment being value objects (immutable) and use constructor injection for instance creation, no default ctor (even private), no private setters, and are Owned Types.


 public sealed class GeoPosition
 {
        public double Latitude { get; }
        public double Longitude { get; }

        public GeoPosition(double latitude, double longitude)
        {
            Latitude = latitude;
            Longitude = longitude;
        }
}

public sealed class GeoSegment
{
        public GeoPosition Start { get; }
        public GeoPosition End { get; }

        public GeoSegment(GeoPosition start, GeoPosition end)
        {
            Start = start;
            End = end;
        }
}

public class MyEntity
{
        public int Id { get; set; }
        public GeoSegment Location { get; set; }

        public MyEntity(GeoSegment location)
        {
            Location = location;
        }
}

The same model example can be considered for issue #12118

@bicatu
Copy link

bicatu commented May 27, 2019

Any update or alternative solution for this?

@ajcvickers
Copy link
Member

@bicatu What is the specific problem for which are you looking for an alternative solution?

This issue is in the Backlog milestone. This means that it is not going to happen for the 3.0 release. We will re-assess the backlog following the 3.0 release and consider this item at that time. However, keep in mind that there are many other high priority features with which it will be competing for resources.

@ajcvickers
Copy link
Member

@bicatu The only alternative solution that EF currently supports is to create a constructor that doesn't take B and then allow EF to set B after creation. The setter for B can be private.

@malohr
Copy link

malohr commented Oct 30, 2019

I ran into the same issue even without using related entities. Found a solution for my case.
Hope this will help you guys.

Quick example:

 public class Event {
        public Event(string subject, DateTime startDate, DateTime endDate, bool enablePrivate)
        {
            Subject = subject;
            StartDate = startDate;
            PrivateEvent = enablePrivate;
            EndDate = endDate;
        }
       
        public string Subject { get; private set; }
        public DateTime StartDate { get; private set; }
        public DateTime EndDate { get; private set; }
        public bool PrivateEvent { get; private set; }
}

This gave me the following exception:
System.InvalidOperationException : No suitable constructor found for entity type 'Event'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'enablePrivate'

So what I have found in the Microsoft docs (https://docs.microsoft.com/de-de/ef/core/modeling/constructors) :
"The parameter types and names must match property types and names, except that properties can be Pascal-cased while the parameters are camel-cased."

In that case the solution was to rename the parameter to "enablePrivate" and the exception was gone.

@M-Pixel
Copy link

M-Pixel commented Mar 9, 2020

Adding support for navigation-property via constructor is essential to accommodating C# 8.0's new nullable reference mode.

modelBuilder.Entity<Workstation>()
    .HasOne(w => w.Owner)
    .WithMany()
    .HasForeignKey("OwnerId");
class Workstation
{
    public User Owner { get; set; } // CS8618 Non-nullable property 'Owner' is uninitialized.
    public string Hostname { get; set; }
}
class Workstation 
{
    public User Owner { get; set; }
    public string Hostname { get; set; }

    public Workstation(User owner, string hostname)
    {
        Owner = owner;
        Hostname = hostname;
    }
}
// Exception: No suitable constructor found for entity type 'Workstation'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'owner' in 'Workstation(User owner, string hostname)'

@andriysavin
Copy link
Author

andriysavin commented Aug 6, 2020

Adding support for navigation-property via constructor is essential to accommodating C# 8.0's new nullable reference mode.

@M-Pixel There is a doc page which describes how to work with NRTs in EF Core (and fix the warning): https://docs.microsoft.com/en-us/ef/core/miscellaneous/nullable-reference-types

@msschl
Copy link

msschl commented Nov 5, 2020

Having exactly the issue mentioned in the sample by @andriysavin above in a real world application.

We have a nested LatLngPoint in the LatLngBounds object. Both are value objects used as owned types in an aggregated root.

public sealed class LatLngPoint : ValueObject<LatLngPoint>
{
    private LatLngPoint(double latitude, double longitude)
    {
        // Argument validation...

        this.Latitude = latitude;
        this.Longitude = longitude;
    }

    public double Latitude { get; }

    public double Longitude { get; }
}

public sealed class LatLngBounds : ValueObject<LatLngBounds>
{
    private LatLngBounds(LatLngPoint southwest, LatLngPoint northeast)
    {
        this.Southwest = southwest ?? throw new ArgumentNullException(nameof(southwest), "...");
        this.Northeast = northeast ?? throw new ArgumentNullException(nameof(northeast), "...");
    }

    public LatLngPoint Southwest { get; }

    public LatLngPoint Northeast { get; }
}

public class Map : IShadowUserAuditableEntity, IAggregateRoot
{
    private Map(Guid id)
    {
        // Argument validation...
        
        this.Id = id;
    }

    public Guid Id { get; }

    public LatLngBounds Viewport { get; }
}

public class MapEntityTypeConfiguration : IEntityTypeConfiguration<Map>
{
    public void Configure(EntityTypeBuilder<Map> builder)
    {
        ...
    
        builder.OwnsOne(e => e.Viewport, builder =>
        {
            builder.OwnsOne(e => e.Southwest, builder =>
            {
                builder.Property(e => e.Latitude)
                    .IsRequired()
                    .HasColumnName("SouthwestLat");

                builder.Property(e => e.Longitude)
                    .IsRequired()
                    .HasColumnName("SouthwestLng");
            });

            builder.OwnsOne(e => e.Northeast, builder =>
            {
                builder.Property(e => e.Latitude)
                    .IsRequired()
                    .HasColumnName("NortheastLat");

                builder.Property(e => e.Longitude)
                    .IsRequired()
                    .HasColumnName("NortheastLng");
            });
        });

        ...
    }
}

Results in:

System.InvalidOperationException: No suitable constructor found for entity type 'LatLngBounds'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'southwest', 'northeast' in 'LatLngBounds(LatLngPoint southwest, LatLngPoint northeast)'.
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.ConstructorBindingConvention.ProcessModelFinalized(IConventionModelBuilder modelBuilder, IConventionContext`1 context)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalized(IConventionModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalized(IConventionModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel()
   at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel()
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_3(IServiceProvider p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(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.DbContext.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.get_Model()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityType()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.CheckState()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityQueryable()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.System.Linq.IQueryable.get_Provider()
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.Include[TEntity,TProperty](IQueryable`1 source, Expression`1 navigationPropertyPath)

Further adding LatLngBounds as a parameter to the Map aggregate root constructor results in:

   System.InvalidOperationException: No suitable constructor found for entity type 'Map'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'viewport', 'mode' in 'Map(Guid id, LatLngBounds viewport, Nullable<MapMode> mode)'; cannot bind 'viewport' in 'Map(Guid id, LatLngBounds viewport, MapMode mode)'.
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.ConstructorBindingConvention.ProcessModelFinalized(IConventionModelBuilder modelBuilder, IConventionContext`1 context)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalized(IConventionModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalized(IConventionModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel()
   at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel()
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_3(IServiceProvider p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(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.DbContext.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.get_Model()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityType()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.CheckState()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityQueryable()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.System.Linq.IQueryable.get_Provider()
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.Include[TEntity,TProperty](IQueryable`1 source, Expression`1 navigationPropertyPath)

@CRodriguez25
Copy link

Yeah I appear to be having the same issue as well. Not sure if this is thought to be resolved? I may be doing something wrong.

@ardalis
Copy link

ardalis commented Mar 12, 2021

This remains an issue in 5.x

@InspiringCode
Copy link

This would be a really useful feature, especially for required one-to-to or many-to-one related entities. Without this feature one could not really validate, whether the entity constructed by EF actually has the required related entity property really set (nullability might be violated)!

nvsnkv added a commit to nvsnkv/flow2 that referenced this issue Nov 6, 2021
issue in EF core dotnet/efcore#12078 makes things worse
@visschersm
Copy link

My issue about this was indeed a duplicate.
Updated my sample to support migration generation with an empty constructor but still using private setters for the properties.
Now only the default constructor gives the NRT warning but nearly there.

@ErroneousFatality
Copy link

ErroneousFatality commented Dec 20, 2021

3 years and 7 months later, this remains an issue in v6.0.1.
I'm using the #nullable setting in projects and now I have to do this: private Entity() { OwnedProperty = default!; }.
Instead of the expected: private Entity(OwnedProperty ownedProperty) { OwnedProperty = ownedProperty; }.

@ajcvickers
Copy link
Member

@ErroneousFatality As in all software development, we have limited resources and have to make hard decisions about what to prioritize. Make sure to vote (👍) for this issue if it is important to you. It currently has 18 votes, which puts it in 78th place in the list of top voted issues.

See The Planning Process for more information on how we decide what to work on.

@yecril71pl
Copy link
Contributor

I am trying to have an explicit many-to-many association (because implicit many-to-many associations create unwanted shadow properties):

[Owned]
class PersonWorkplace {
 Person RefPerson { get; } Workplace RefWorkplace { get; }
 public PersonWorkpace (Person refPerson, Workplace refWorkplace) {}}

It feels like basic stuff (like WMI-style associations) does not work 😞

System.InvalidOperationException: No suitable constructor was found for entity type 'MedicWorkplace'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'refMedic', 'refWorkplace' in 'MedicWorkplace(Medic refMedic, Workplace refWorkplace)'.
         at Microsoft.EntityFrameworkCore.Metadata.Internal.ConstructorBindingFactory.GetBindings(IReadOnlyEntityType entityType, Func`5 bind, InstantiationBinding& constructorBinding, InstantiationBinding& serviceOnlyBinding)
         at Microsoft.EntityFrameworkCore.Metadata.Internal.ConstructorBindingFactory.GetBindings(IMutableEntityType entityType, InstantiationBinding& constructorBinding, InstantiationBinding& serviceOnlyBinding)
         at Microsoft.EntityFrameworkCore.Metadata.Conventions.ConstructorBindingConvention.ProcessModelFinalizing(IConventionModelBuilder modelBuilder, IConventionContext`1 context)
         at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalizing(IConventionModelBuilder modelBuilder)
         at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalizing(IConventionModelBuilder modelBuilder)
         at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel()
         at Microsoft.EntityFrameworkCore.Infrastructure.ModelRuntimeInitializer.Initialize(IModel model, Boolean designTime, IDiagnosticsLogger`1 validationLogger)
         at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, ModelCreationDependencies modelCreationDependencies, Boolean designTime)
         at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel(Boolean designTime)
         at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
         at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__8_4(IServiceProvider p)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass2_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
         at Microsoft.Extensions.DependencyInjection.ServiceProvider.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_ContextServices()
         at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
         at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
         at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.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.DbContextActivator.CreateInstance(Type contextType, Assembly startupAssembly, IOperationReportHandler reportHandler, String[] args)
         at Microsoft.EntityFrameworkCore.Design.DbContextActivator.CreateInstance(Type contextType, Assembly startupAssembly, IOperationReportHandler reportHandler)
         at Microsoft.VisualStudio.Web.CodeGeneration.EntityFrameworkCore.EntityFrameworkModelProcessor.TryCreateContextUsingAppCode(Type dbContextType, Type startupType) in /home/dell/prog/Scaffolding/src/Scaffolding/VS.Web.CG.EFCore/EntityFrameworkModelProcessor.cs:line 685

@yecril71pl
Copy link
Contributor

3 years and 7 months later, this remains an issue in v6.0.1. I'm using the #nullable setting in projects and now I have to do this: private Entity() { OwnedProperty = default!; }. Instead of the expected: private Entity(OwnedProperty ownedProperty) { OwnedProperty = ownedProperty; }.

I would even say

[Obsolete ("see <URL: https://github.com/dotnet/efcore/issues/12078 >")]
private Entity() { OwnedProperty = default!; }

@InspiringCode

This comment was marked as off-topic.

@ajcvickers

This comment was marked as off-topic.

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