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

Migration ef core 2.2 to 3.1 with owned entities #19789

Closed
michielpeeters opened this issue Feb 4, 2020 · 8 comments
Closed

Migration ef core 2.2 to 3.1 with owned entities #19789

michielpeeters opened this issue Feb 4, 2020 · 8 comments
Labels
closed-no-further-action The issue is closed and no further action is planned. customer-reported

Comments

@michielpeeters
Copy link

Observed Behavior

I'm struggling with one of the breaking changes from ef core 2.2 to ef core 3.1. The breaking change that I'm talking about is the 'Owned' breaking change. I've tried many settings to resolve the problem that I'm facing, but until now, nothing has worked. My question is what must I do so that I can migrate from ef core 2.2 to ef core 3.1 succesfully (so that I'm able to use my context in the application without any data loss)?

I've managed to create a small test project where my problem is located which can be found here:
repository

I've tried and read the solutions from other people, but still no success:

#18092 #15681 #9873

https://stackoverflow.com/questions/57692369/ef-core-configuration-problem-with-owned-type-used-in-2-different-classes
https://docs.microsoft.com/en-us/ef/core/modeling/owned-entities

The error that I'm experiencing is as follow:

PM> Add-Migration Test
Build started...
Build succeeded.
System.InvalidOperationException: The type 'ContactInfo' cannot be configured as non-owned because an owned entity type with the same name already exists.
   at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalModelBuilder.Entity(TypeIdentity& type, ConfigurationSource configurationSource, Nullable`1 shouldBeOwned)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalModelBuilder.Entity(Type type, ConfigurationSource configurationSource, Nullable`1 shouldBeOwned)
   at Microsoft.EntityFrameworkCore.ModelBuilder.Entity[TEntity]()
   at TestProject.Context.TestDbContext.OnModelCreating(ModelBuilder modelBuilder) in C:\Users\mmpeeters\source\repos\TestProject\TestProject\Context\TestDbContext.cs:line 18
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelCustomizer.Customize(ModelBuilder modelBuilder, DbContext context)
   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.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 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 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.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.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.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_0.<.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)
The type 'ContactInfo' cannot be configured as non-owned because an owned entity type with the same name already exists.

The main question is, what can I do to resolve this error? :-)

Expected Behavior

That I'm able to run migrations and even better that I'm able to use the DbContext in the web project without this error.

Steps to reproduce

Github project: repository

Further technical details

EF Core version: 3.1.1
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET Core 3.1
Operating system: Windows 10
IDE: Visual Studio 2019 Preview 16.5.0 (Preview 2)

@ajcvickers
Copy link
Member

@michielpeeters The top-level Entity method cannot be used to configure an owned type. So, instead of this:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<BigCustomer>().OwnsOne(c => c.Info);
    modelBuilder.Entity<SmallCustomer>().OwnsOne(c => c.Info); 
    modelBuilder.Entity<ProjectCustomer>().OwnsOne(c => c.Info);
   
    modelBuilder.Entity<ContactInfo>()
        .Property<byte[]>("RowVersion").IsRowVersion().HasColumnName("RowVersion");
    
    base.OnModelCreating(modelBuilder);
}

Do this:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<BigCustomer>()
        .OwnsOne(
            c => c.Info, 
            b=> b.Property<byte[]>("RowVersion").IsRowVersion().HasColumnName("RowVersion"));
 
    
    modelBuilder
        .Entity<SmallCustomer>()
        .OwnsOne(
            c => c.Info, 
            b=> b.Property<byte[]>("RowVersion").IsRowVersion().HasColumnName("RowVersion"));
 
    modelBuilder
        .Entity<ProjectCustomer>()
        .OwnsOne(
            c => c.Info, 
            b=> b.Property<byte[]>("RowVersion").IsRowVersion().HasColumnName("RowVersion"));
    base.OnModelCreating(modelBuilder);
}

However, that's not working for me either. @AndriySvyryd Any ideas?

Code:

[Table("Customers")]
public abstract class CustomerBase
{
    [Key]
    public int Id { get; set; }

    [Required]
    public string Name { get; set; }

    [Timestamp]
    public byte[] RowVersion { get; set; }
}

public class BigCustomer : CustomerBase
{
    public ContactInfo Info { get; set; }
}

[Owned]
public class ContactInfo
{
    [Required]
    public string FirstName { get; set; }

    [Required]
    public string LastName { get; set; }

    [Required]
    public string Email { get; set; }
}

public class ProjectCustomer : CustomerBase
{
    public ContactInfo Info { get; set; }
}

public class SmallCustomer : CustomerBase
{
    public ContactInfo Info { get; set; }
}

public class BloggingContext : DbContext
{
    private readonly ILoggerFactory Logger 
        = LoggerFactory.Create(c => c.AddConsole());//.SetMinimumLevel(LogLevel.Debug));

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder
            .UseLoggerFactory(Logger)
            .EnableSensitiveDataLogging()
            .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<CustomerBase>();

        modelBuilder
            .Entity<BigCustomer>()
            .OwnsOne(
                c => c.Info, 
                b=> b.Property<byte[]>("RowVersion").IsRowVersion().HasColumnName("RowVersion"));
        
        modelBuilder
            .Entity<SmallCustomer>()
            .OwnsOne(
                c => c.Info, 
                b=> b.Property<byte[]>("RowVersion").IsRowVersion().HasColumnName("RowVersion"));
     
        modelBuilder
            .Entity<ProjectCustomer>()
            .OwnsOne(
                c => c.Info, 
                b=> b.Property<byte[]>("RowVersion").IsRowVersion().HasColumnName("RowVersion"));

        base.OnModelCreating(modelBuilder);
    }
}

public class Program
{
    public static async Task Main()
    {
        using (var context = new BloggingContext())
        {
            context.Database.EnsureDeleted();
            context.Database.EnsureCreated();
        }
    }
}

Exception:

s\dotnet\dotnet.exe" C:/Stuff/Local/ThreeOne/bin/Debug/netcoreapp3.1/ThreeOne.dll
application data, this mode should only be enabled during development.
Unhandled exception. System.InvalidOperationException: Entity type 'BigCustomer' doesn't contain a property mapped to the store-generated concurrency token column 'RowVersion' that is used by
another entity type sharing the table 'Customers'. Add a store-generated property mapped to the same column to 'BigCustomer'. It can be in shadow state.
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.ValidateSharedColumnsCompatibility(IReadOnlyList`1 mappedTypes, String tableName, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.SqlServer.Internal.SqlServerModelValidator.ValidateSharedColumnsCompatibility(IReadOnlyList`1 mappedTypes, String tableName, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.ValidateSharedTableCompatibility(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.SqlServer.Internal.SqlServerModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.ValidatingConvention.ProcessModelFinalized(IConventionModelBuilder modelBuilder, IConventionContext`1 context)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalized(IConventionModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalied(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.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProv
iderEngine, 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 callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProv
iderEngine, 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.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.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.get_Dependencies()
   at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.EnsureDeleted()
   at Program.Main() in C:\Stuff\Local\ThreeOne\Program.cs:line 114
   at Program.<Main>()

@AndriySvyryd
Copy link
Member

You also need to map the RowVersion on CustomerBase to the same column:

modelBuilder.Entity<CustomerBase>()
    .Property(c => c.RowVersion).HasColumnName("RowVersion");

@ajcvickers Do you think that the exception message should be improved?

@ajcvickers
Copy link
Member

@AndriySvyryd Maybe. I should have tried explicitly mapping it, but I was expecting to already map to that column. Why does it need explicit configuration here? Is it because RowVersion is explicitly mapped by other types, so we then uniquify the by-convention mapping for the column name?

@AndriySvyryd
Copy link
Member

Why does it need explicit configuration here? Is it because RowVersion is explicitly mapped by other types, so we then uniquify the by-convention mapping for the column name?

Yes. We uniquify all names not specified explicitly if there's a collision.

@ajcvickers ajcvickers added the closed-no-further-action The issue is closed and no further action is planned. label Feb 4, 2020
@michielpeeters
Copy link
Author

Thank you for the responses. I was able to resolve my problem! Maybe it is an idea to mention that uniquify in the documentation?

@clouddust0246
Copy link

hello is this issue being resolved?

i tried handled the owned entities and i am returning with the same error.

System.InvalidOperationException: The type 'SamuraiApp.Domain.PersonFullName' cannot be configured as non-owned because an owned entity type with the same name already exists.
at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalModelBuilder.Entity(TypeIdentity& type, ConfigurationSource configurationSource, Nullable1 shouldBeOwned) at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalModelBuilder.Entity(String name, ConfigurationSource configurationSource, Nullable1 shouldBeOwned)
at Microsoft.EntityFrameworkCore.ModelBuilder.Entity(String name)
at SamuraiAppEF.Data.SamuraiContext.OnModelCreating(ModelBuilder modelBuilder) in C:\Users\clouddust-dell\source\repos\SamuraiApp\SamuraiApp\SamuraiAppEF.Data\SamuraiContext.cs:line 74
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.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 callSite, 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 callSite, 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.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.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure1 accessor) at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func1 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.OperationBase.<>c__DisplayClass3_0`1.b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
The type 'SamuraiApp.Domain.PersonFullName' cannot be configured as non-owned because an owned entity type with the same name already exists.

Code:
`

public class Battle
{
	public Battle() {
		SamuraiBattles = new List<SamuraiBattle>();
	}
	public int Id { get; set; }
	public string Name { get; set; }
	public DateTime StartDate { get; set; }
	public DateTime EndDate { get; set; }
	//public List<Samurai> Samurais { get; set; }
	public List<SamuraiBattle> SamuraiBattles { get; set; }
}

public class SecretIdentity
{
	public int Id { get; set; }
	public string RealName { get; set; }
	//public int? SamuraiFK { get; set; } //Question mark allows nullubale dependents
	//
	public int SamuraiId { get; set; }

	//public Samurai Samurai { get; set; }//if you want to navigate secret identity to samurai
}

public class Quote
{
	public int Id { get; set; }
	public string Text { get; set; }
	public Samurai Samurai { get; set; }
	public int SamuraiId { get; set; }
}

public class SamuraiBattle
{
	public int SamuraiId { get; set; }
	public Samurai Samurai { get; set; }
	public int BattleId { get; set; }
	public Battle Battle { get; set; }
}
[Owned]
public class PersonFullName
{
	public PersonFullName(string givenName, string surName) {
		SurName		= surName;
		GivenName	= givenName;
	}
	public string SurName { get; set; }
	public string GivenName { get; set; }
}

public class Samurai : ITimeStamp
{
	public Samurai() {
		Quotes = new List<Quote>();
		SamuraiBattles = new List<SamuraiBattle>();
	}
	//if e require gyd and one to one use business logic
	public Samurai(string publicName, string secretName) : this() {
		Name = publicName;
		SecretIdentity = new SecretIdentity { RealName = secretName };
	}
	//
	public int Id { get; set; }
	public string Name { get; set; }
	public string LastName { get; set; }
	public PersonFullName BetterName { get; set; }
	//
	public List<Quote> Quotes { get; set; }
	public List<SamuraiBattle> SamuraiBattles { get; set; }
	public SecretIdentity SecretIdentity { get; set; }
	//
	public DateTime DateCreated { get; set; }
	public DateTime DateUpdated { get; set; }
	//
	public string CompleteName => LastName + ", " + Name;
	//
}

`

Context Class:

`
public SamuraiContext()
{

	}
			
	public DbSet<Samurai> Samurais { get; set; }
	public DbSet<Quote> Quotes { get; set; }
	public DbSet<Battle> Battles { get; set; }

	protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
		optionsBuilder
			.UseMySql(_connectionString);
	}

	protected override void OnModelCreating(ModelBuilder modelBuilder) {
		modelBuilder.Entity<SamuraiBattle>(entity => {
			entity.HasKey(s => new { s.SamuraiId, s.BattleId });
		});
		modelBuilder.Entity<Battle>().Property(c => c.StartDate).HasColumnType("Date");
		modelBuilder.Entity<Battle>().Property(c => c.EndDate).HasColumnType("Date");
		//
		modelBuilder.Entity<Samurai>(entity => {
			entity.UseTimestampedProperty();
			entity.HasKey(e => e.Id);
			entity.OwnsOne(m => m.BetterName);
		});
		foreach (var entityType in modelBuilder.Model.GetEntityTypes()) {
			modelBuilder.Entity(entityType.Name).Property<DateTime>("Created");
			modelBuilder.Entity(entityType.Name).Property<DateTime>("LastModified");
		}

	}

`

Some handling for shadow properties are also being implemented.

@AndriySvyryd
Copy link
Member

AndriySvyryd commented Apr 27, 2020

@clouddust0246 Don't call modelBuilder.Entity(entityType.Name), instead configure the properties in the OwnsOne call. See docs

@mahermali
Copy link

I had the same issue, and the fix was as following.
After changing the configuration to 3.0 the end result should be any empty migration, which means the model hasn't been changed.

the model I was working on is the following:

public class SchedulerSession:AggregateRoot
    {
        public List<SchedulerSessionStep> Steps { get; set; }
        public double ElapsedSeconds { get; set; }
        public List<SchedulerSessionCounter> Counters { get; set; }
    }

public class SchedulerSessionStep 
    {
        public string Name { get; set; }
        public double ElapsedSeconds { get; set; }
        public List<SchedulerSessionStepError> Errors { get; set; }
    }
 public class SchedulerSessionStepError
    {
        public string Error { get; set; }
        public string Description { get; set; }
        public string Exception { get; set; }
        public string StackTrace { get; set; }
    }
public class SchedulerSessionCounter
    {
        public string Name { get; set; }
        public int Value { get; set; }
    }

The configuration I used was:

modelBuilder.Entity<SchedulerSession>().OwnsOne(s => s.Changes);
modelBuilder.Entity<SchedulerSession>().OwnsMany(s => s.Steps);
modelBuilder.Entity<SchedulerSessionStep>().OwnsMany(ss => ss.Errors);
modelBuilder.Entity<SchedulerSession>().OwnsMany(s => s.Counters);
            
modelBuilder.Entity<SchedulerSessionStep>().Property<int>("Id");
modelBuilder.Entity<SchedulerSessionStep>().HasKey("Id");
modelBuilder.Entity<SchedulerSessionStepError>().Property<int>("Id");
modelBuilder.Entity<SchedulerSessionStepError>().HasKey("Id");
modelBuilder.Entity<SchedulerSessionCounter>().Property<int>("Id");
modelBuilder.Entity<SchedulerSessionCounter>().HasKey("Id");

The new configuration:

modelBuilder.Entity<SchedulerSession>().OwnsOne(session => session.Changes);
modelBuilder.Entity<SchedulerSession>().OwnsMany(session => session.Steps, step =>
            {
                step.Property<int>("Id");
                step.HasKey("Id");
                step.OwnsMany(s => s.Errors, error =>
                {
                    error.Property<int>("Id");
                    error.HasKey("Id");
                }).WithOwner();
            });
modelBuilder.Entity<SchedulerSession>().OwnsMany(session => session.Counters, counter =>
            {
                counter.Property<int>("Id");
                counter.HasKey("Id");
            });

Add a migration and call it Sync to test.
The result was a migration with all tables created again.

After some investigation, I found there were some changes to the file: ApplicationDbContextModelSnapshot

The changes apparently not changing the model, but changing Model builder version to 3.1.4:

modelBuilder
                .HasAnnotation("ProductVersion", "3.1.4")
                .HasAnnotation("Relational:MaxIdentifierLength", 128)
                .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);

And some changes related to defining columns properties, for example:

b.Property<Guid>("AggregateId");

Becomes

 b.Property<Guid>("AggregateId")
                        .HasColumnType("uniqueidentifier");

I deleted the sync migration.

Added it again and it was empty.

Delete the second migration since it's empty.

Run the application and it was intact.

Hope this will help someone.

@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
Labels
closed-no-further-action The issue is closed and no further action is planned. customer-reported
Projects
None yet
Development

No branches or pull requests

5 participants