Efcore: [Question] Where do column names get generated?

Created on 2 May 2019  路  24Comments  路  Source: dotnet/efcore

Describe what is not working as expected.

I am losing many hours and sleep debugging a showstopping issue for me. I have tried creating a repro test case, but the test case consistently passes. I'm looking for guidance on how I can find what line of code assigns column names to entities in the change tracking engine. Ideally I'd like to add a Breakpoint there, and instead of loading the EFCore nuget package, load the GItHub source locally and figure out how this is happening. - Either My stack trace is happening too late for me to see that there is a model mapping error somewhere, or EFCore has multiple places where it can generate a column name, and those places are not consistent.

If you are seeing an exception, include the full exceptions details (message and stack trace).

Error Message:
Microsoft.EntityFrameworkCore.DbUpdateException : An error occurred while updating the entries. See the inner exception for details.
---- System.Data.SqlClient.SqlException : Invalid column name 'GoodChild_ChildId'.
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(DbContext _, ValueTuple`2 parameters)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable`1 commandBatches, IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IReadOnlyList`1 entriesToSave)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at JohnZabroski.Data.Context.DbContextBase.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at JohnZabroski.Data.Testing.Specifications.PersistenceSpecification`1.Verify(VerifyParameters parameters, TEntity entity)
   at JohnZabroski.Data.Testing.Configurations.EntityConfigurationTestBase`1.TestConfiguration()
----- Inner Stack Trace -----
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
   at System.Data.SqlClient.SqlDataReader.get_MetaData()
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
   at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues)
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteReader(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)

Steps to reproduce

I can't yet reproduce the issue. Creating a smaller issue, the problem does not show up. I suspect it has something to do with proxies, since the failure happens in my test suite with AutoFixture.

Further technical details

EF Core version: 2.2.4
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
Operating system: Windows 10 Pro
IDE: Visual Studio 2017 15.9.11

closed-question customer-reported

All 24 comments

Hmm... I made some progress... immediately after filing this, I modified the my modelBuilder logic slightly and it worked - after 35 hours of debugging. Going to perform the Ostrich move now and stick my head in the sand.

The problem appears to be specific to having to, under certain conditions (that I cannot figure out), in a TPH you need to re-map the Id column for every child class and the parent base class.

Specifically, on the base class I do:

builder.HasKey(x => x.Id);
            builder.Property<long>(x => x.Id).HasColumnName("ChildId").UseSqlServerIdentityColumn<long>().ValueGeneratedOnAdd();

on the child classes, do:

builder.Property(x => x.Id).HasColumnName("ChildId"); // I'm not sure why doing this is necessary, and it seems to be required to do on all leaf entities

I have a hunch the primary reason I cannot reproduce this might have to do something with the fact that in the non-repro test case, I am generating the DB using EF, whereas in the repro (real world) code, I am using FluentMigrator. Specifically, when the column names are not picked by EF, and you are defining a foreign key relationship, you have to explicitly define the column names on every property on every entity participating in that key relationship (that is to say, both sides of the relationship). I'm not sure exactly why that would be the case, but the documentation on foreign key modeling says:

By convention, foreign key constraints are named FK_<dependent type name>_<principal type name>_<foreign key property name>. For composite foreign keys <foreign key property name> becomes an underscore separated list of foreign key property names.

It seems like somehow I am hitting this code path in the system, when I should not necessarily hit it. Perhaps Table-per-hierarchy is triggering this code path?

@jzabroski I am guessing that ChildId is defined on an abstract base class. Then you are hitting https://github.com/aspnet/EntityFrameworkCore/issues/14055. But in general we add the prefix if you have two properties with the same name defined on different types mapped to the same table. It's safer to assume they should be mapped to different columns.

FYI you can call modelBuilder.Model.ToDebugString(); at the end of OnModelCreating to print out the whole model in case this helps with debugging.

Oh my god, that last tip! THANK YOU SO MUCH!!

To rephrase what you are saying, I am trying to workaround #14055 by mapping ChildId on both leaf entities, but the code is re-mapping that to different columns "to be safe"?

@jzabroski Yes, though when the property comes from a base type prefixing is overkill, so we don't do it anymore starting with 3.0.0-preview4

Any chance you can point me to the PR that fixes this so I can take a look?

when the property comes from a base type prefixing is overkill,

I think prefixing is overkill also in "bring your own database" model. For database-first, why are you injecting magic strings into my mapping definitions? This is extremely confusing behavior to me. I've looked all over the EFCore code base trying to understand this, but searching for "_" is a needle in a haystack. There are 35 possible candidates when I Control+Shift+F in Visual Studio for the literal string "_".

@jzabroski See https://github.com/aspnet/EntityFrameworkCore/pull/14818/files#diff-f4a2e4aff9077e040c99b0a14f81c350R231
We don't currently have a different set of conventions for "bring your own database", it could be something like https://github.com/aspnet/EntityFrameworkCore/issues/1414

@AndriySvyryd I'm saying something much simpler - I just want a "Please don't add prefixes" mode. Bring your own conventions (#1414, #214 ) seems like a lot of API surface area to cover. I believe based on my experiences working with EFCore in October/November and the last week that I don't need anything that fancy to be able to do "bring your own database".

Put another way, I'm very surprised that HasColumnName("ChildId") maps to any column name other than... ChildId. I don't feel like this was the intent of getting rid of BasicModelBuilder?

@jzabroski Well that's the convention that doesn't fit your database, but other databases might be conflicting with other conventions. We try to add features that are as general as possible to avoid having a lot of small dials. We are already making good progress on #214, so I expect that it will be released in 3.x timeframe (not 3.0 though)

Cool! Is it in a public branch where I can look and perhaps contribute?

The infrastructure changes are in master, but the API to actually change the conventions has not been designed yet

Another feature that would help is https://github.com/aspnet/EntityFrameworkCore/issues/831, it would take your current model and basically apply any changes necessary to make it compatible with the database.

The infrastructure changes are in master, but the API to actually change the conventions has not been designed yet

Ah, I see - I found https://github.com/aspnet/EntityFrameworkCore/pull/15229 as well as comments from 2015 where #908 where Migrations were using the BasicModelBuilder.

Not sure if you've seen how Fluent-NHibernate does this stuff, but it's a bit more descriptive in that they box up the MemberInfo into a Member object along with other information that you'd want at your fingertips. Then you pass the Member to your standard conventions and let people write custom conventions off the Member type - it works really well since there is less "digging" to map stuff. Everything is pre-surfaced.

Not sure if you've seen how Fluent-NHibernate does this stuff, but it's a bit more descriptive in that they box up the MemberInfo into a Member object along with other information that you'd want at your fingertips. Then you pass the Member to your standard conventions and let people write custom conventions off the Member type - it works really well since there is less "digging" to map stuff. Everything is pre-surfaced.

@jzabroski From a glance it looks similar to EF6 Custom Conventions. While it's useful in some cases it hasn't been requested much for EF Core, see https://github.com/aspnet/EntityFrameworkCore/issues/9117.

@AndriySvyryd Re-opening this as I think I found a bug in 3.0.0-preview4 based on your comment:

@jzabroski Yes, though when the property comes from a base type prefixing is overkill, so we don't do it anymore starting with 3.0.0-preview4

I just tried 3.0.0-preview4 from nuget.org, and it broke something different. - And probably in a much worse/severe way. But the error message is super awesome (even if it's incorrect!)!

Describe the problem

Can't configure TPH in EFCore 3.0.0-preview4 unless I am round-tripping my entire database using EF migrations.

Steps to Reproduce

I do not have enough time left this week to produce a full repro, and due to troubleshooting EF conventions, I likely can't devote more time to it for at least another 2 weeks while I get my projects back on timeline. However, suffice to say, I think based on your description, the new 3.0.0-preview4 logic will fail if you modify my example in #15553 and move the Id property into a marker ABC, like the C# below.

Note to self: I think the issue may be if you do Property<long>(x => x.Id).HasColumnName<long>("ParentId") in the ABC, and omit the generic type parameter in HasColumnName in the concrete leaf classes. - I believe the lack of a closed type parameter on this method causes the nullability error to surface.

public abstract class EntityBase
{
  public virtual long Id {get;set;}
}
public interface IHasTimeStamp
{
  DateTime DateCreated { get; set; }
  DateTime DateModified { get; set; }
}
public abstract class EntityWithTimeStampBase : EntityBase, IHasTimeStamp
{
    public virtual DateTime DateCreated { get; set; }
    public virtual DateTime DateModified { get; set; }
}
private abstract class ParentBase : EntityBase
        {
            public ParentDiscriminator Discriminator { get; protected set; }
        }

        private class GoodParent : ParentBase
        {
            public GoodParent()
            {
                Discriminator = ParentDiscriminator.Good;
            }
            public virtual GoodChild Child { get; set; }
            public virtual string GoodParentData { get; set; }
        }

        private class BadParent : ParentBase
        {
            public BadParent()
            {
                Discriminator = ParentDiscriminator.Bad;
            }
            public virtual BadChild Child { get; set; }
            public virtual string BadParentData { get; set; }
        }

        private abstract class ChildBase : EntityBase
        {
            public ParentChildDiscriminator ChildDiscriminator { get; protected set; }
        }

        private class GoodChild : ChildBase
        {
            public GoodChild()
            {
                ChildDiscriminator = ParentChildDiscriminator.Good;
            }
            public virtual GoodParent Parent { get; set; }
            public virtual string GoodChildData { get; set; }
        }

        private class BadChild : ChildBase
        {
            public BadChild()
            {
                ChildDiscriminator = ParentChildDiscriminator.Bad;
            }
            public virtual BadParent Parent { get; set; }
            public virtual string BadChildData { get; set; }
        }
System.InvalidOperationException : 'GoodParent.ParentId' and 'ParentBase.Id' are both mapped to column 'ParentId' in 'dbo.ParentBase' but are configured with different nullability.
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.ValidateSharedColumnsCompatibility(IReadOnlyList`1 mappedTypes, String tableName, DiagnosticsLoggers loggers)
   at Microsoft.EntityFrameworkCore.SqlServer.Internal.SqlServerModelValidator.ValidateSharedColumnsCompatibility(IReadOnlyList`1 mappedTypes, String tableName, DiagnosticsLoggers loggers)
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.ValidateSharedTableCompatibility(IModel model, DiagnosticsLoggers loggers)
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model, DiagnosticsLoggers loggers)
   at Microsoft.EntityFrameworkCore.SqlServer.Internal.SqlServerModelValidator.Validate(IModel model, DiagnosticsLoggers loggers)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ValidatingConvention.Apply(InternalModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelBuilt(InternalModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel()
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator, DiagnosticsLoggers loggers)
   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, DiagnosticsLoggers loggers)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite scopedCallSite, 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.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite scopedCallSite, 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.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_ExecutionStrategyFactory()
   at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.CreateExecutionStrategy()
   at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.BeginTransaction(DatabaseFacade databaseFacade, IsolationLevel isolationLevel)
   at JohnZabroski.Data.Testing.PersistenceTestBase`1..ctor()
   at JohnZabroski.Data.Testing.Configurations.EntityConfigurationTestBase`1..ctor()
   at JohnZabroski.Data.Tests.Configurations.Parents.GoodParentConfigurationTests..ctor()

@jzabroski I don't think that it has to do with whether HasColumnName is called with generic type parameter or not, but rather a property of different type being mapped to the same column. I don't see GoodParent.ParentId in your code.

It's in modelBuilding logic - I don't have time to play with it to get the full repro but I am writing notes down so I don't forget. This stuff is SUPER FINICKY so i need to write notes somewhere.

I can't remove the HasColumnName mapping, because then I get this error instead - so figuring out a minimal repro is a major time sink and I have to move on.

Microsoft.EntityFrameworkCore.DbUpdateException : An error occurred while updating the entries. See the inner exception for details.
---- System.Data.SqlClient.SqlException : Cannot insert the value NULL into column 'ParentId', table 'Parents_UnitTest.dbo.Child'; column does not allow nulls. INSERT fails.
The statement has been terminated.
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(DbContext _, ValueTuple`2 parameters)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable`1 commandBatches, IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IList`1 entriesToSave)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at JohnZabroski.Data.Context.DbContextBase.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at JohnZabroski.Data.Tests.DataInitializers.Parents.GoodParentDataTest.DoIt() in D:\source\JohnZabroski\trunk\Source\JohnZabroski.Data.Tests\DataInitializers\Parents\GoodParentDataTest.cs:line 51
----- Inner Stack Trace -----
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
   at System.Data.SqlClient.SqlDataReader.get_MetaData()
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
   at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)

@jzabroski That exceptions means that you probably declared Child.ParentId as long instead of long?. The model configuration is usually straightforward once you get familiar with the conventions.

FYI you can call modelBuilder.Model.ToDebugString(); at the end of OnModelCreating to print out the whole model in case this helps with debugging.

This turned out not to be as useful as I hoped. The crux of the problem is that db.Model.ToDebugString() has to... build a model successfully without InvalidOperationException errors... in order to print it's model as a debug string.


Click to see stack trace caused by db.Model.ToDebugString();

System.InvalidOperationException : 'GoodParent.ParentId' and 'ParentBase.Id' are both mapped to column 'ParentId' in 'dbo.ParentBase' but are configured with different nullability.
at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.ValidateSharedColumnsCompatibility(IReadOnlyList1 mappedTypes, String tableName, DiagnosticsLoggers loggers) at Microsoft.EntityFrameworkCore.SqlServer.Internal.SqlServerModelValidator.ValidateSharedColumnsCompatibility(IReadOnlyList1 mappedTypes, String tableName, DiagnosticsLoggers loggers)
at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.ValidateSharedTableCompatibility(IModel model, DiagnosticsLoggers loggers)
at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model, DiagnosticsLoggers loggers)
at Microsoft.EntityFrameworkCore.SqlServer.Internal.SqlServerModelValidator.Validate(IModel model, DiagnosticsLoggers loggers)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ValidatingConvention.Apply(InternalModelBuilder modelBuilder)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelBuilt(InternalModelBuilder modelBuilder)
at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel()
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator, DiagnosticsLoggers loggers)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.<>c__DisplayClass5_0.b__1()
at System.Lazy1.ViaFactory(LazyThreadSafetyMode mode) at System.Lazy1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
at System.Lazy1.CreateValue() at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator, DiagnosticsLoggers loggers) at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel() at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model() at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite scopedCallSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite scopedCallSite, 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.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredServiceT
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 JohnZabroski.Data.Tests.DataInitializers.Parents.GoodParentDataTest.DoIt() in D:\source\JohnZabroski\trunk\Source\JohnZabroski.Data.Tests\DataInitializers\Parents\GoodParentDataTest.cs:line 49

@jzabroski That exceptions means that you probably declared Child.ParentId as long instead of long?. The model configuration is usually straightforward once you get familiar with the conventions.

I did not do that. It's long to long - no long?. In fact, nothing is long? anywhere in the code base. I've even asked multiple developers to be my "rubber duck" and look at the code.

What I am wishing is that I just talked my boss/management team into using EFCore Migrations for this project from the get-go, but I had no idea I was going to hit all these snafus. EFCore Migrations are remarkably easy to use for brand new projects, but for existing projects or database-first, EFCore Metadata is a complete showstopper.

This turned out not to be as useful as I hoped. The crux of the problem is that db.Model.ToDebugString() has to... build a model successfully without InvalidOperationException errors... in order to print it's model as a debug string.

ToDebugString() is not in that stack trace

I did not do that. It's long to long - no long?. In fact, nothing is long? anywhere in the code base.

Yes, that's the issue. If you have an optional FK to a long it has to be long?

Yes, that's the issue. If you have an optional FK to a long it has to be long?

Ah! Thank you so much!

ToDebugString() is not in that stack trace

Of course, because get_Model() is what fails, so it never reaches ToDebugString - that's my point. See this:

at Microsoft.EntityFrameworkCore.DbContext.get_Model()

Of course, because get_Model() is what fails, so it never reaches ToDebugString - that's my point.

FinalizeModel() runs after OnModelCreating() so ToDebugString() ran before that exception was thrown.

OK, will try to confirm that.

@jzabroski You need to get the model from the modelBuilder, not from the context.

馃 馃う鈥嶁檪

Was this page helpful?
0 / 5 - 0 ratings