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

EFCore 7.0.0 - Graph of entity insertion throws a FK exception #29741

Closed
AlexandreRevel opened this issue Dec 2, 2022 · 6 comments
Closed

EFCore 7.0.0 - Graph of entity insertion throws a FK exception #29741

AlexandreRevel opened this issue Dec 2, 2022 · 6 comments
Labels
area-model-building closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported Servicing-approved type-bug
Milestone

Comments

@AlexandreRevel
Copy link

When trying to insert an entity with it's parent , efcore tries to insert two entities in one go, the twos have a relationship with a foreign key references. Maybe the mix of TPC and TPH trigger this error?

Repo for reproduction : https://github.com/AlexandreRevel/EfCoreBug

Stack traces

warn: 02/12/2022 12:04:21.954 CoreEventId.SensitiveDataLoggingEnabledWarning[10400] (Microsoft.EntityFrameworkCore.Infrastructure)
      Sensitive data logging is enabled. Log entries and exception messages may include sensitive application data; this mode should only be enabled during development.
dbug: 02/12/2022 12:04:22.266 CoreEventId.ContextInitialized[10403] (Microsoft.EntityFrameworkCore.Infrastructure)
      Entity Framework Core 7.0.0 initialized 'MyContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer:7.0.0' with options: QuerySplittingBehavior=SplitQuery SensitiveDataLoggingEnabled
dbug: 02/12/2022 12:04:22.312 RelationalEventId.ConnectionCreating[20005] (Microsoft.EntityFrameworkCore.Database.Connection)
      Creating DbConnection.
dbug: 02/12/2022 12:04:22.416 RelationalEventId.ConnectionCreated[20006] (Microsoft.EntityFrameworkCore.Database.Connection)
      Created DbConnection. (110ms).
dbug: 02/12/2022 12:04:22.423 RelationalEventId.ConnectionOpening[20000] (Microsoft.EntityFrameworkCore.Database.Connection)
      Opening connection to database 'EFCore.Test' on server 'localhost'.
dbug: 02/12/2022 12:04:22.943 RelationalEventId.ConnectionOpened[20001] (Microsoft.EntityFrameworkCore.Database.Connection)
      Opened connection to database 'EFCore.Test' on server 'localhost'.
dbug: 02/12/2022 12:04:22.958 RelationalEventId.CommandCreating[20103] (Microsoft.EntityFrameworkCore.Database.Command)
      Creating DbCommand for 'ExecuteNonQuery'.
dbug: 02/12/2022 12:04:22.973 RelationalEventId.CommandCreated[20104] (Microsoft.EntityFrameworkCore.Database.Command)
      Created DbCommand for 'ExecuteNonQuery' (12ms).
dbug: 02/12/2022 12:04:23.005 RelationalEventId.CommandInitialized[20106] (Microsoft.EntityFrameworkCore.Database.Command)
      Initialized DbCommand for 'ExecuteNonQuery' (52ms).
dbug: 02/12/2022 12:04:23.014 RelationalEventId.CommandExecuting[20100] (Microsoft.EntityFrameworkCore.Database.Command)
      Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT 1
info: 02/12/2022 12:04:23.054 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (43ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT 1
dbug: 02/12/2022 12:04:23.058 RelationalEventId.ConnectionClosing[20002] (Microsoft.EntityFrameworkCore.Database.Connection)
      Closing connection to database 'EFCore.Test' on server 'localhost'.
dbug: 02/12/2022 12:04:23.073 RelationalEventId.ConnectionClosed[20003] (Microsoft.EntityFrameworkCore.Database.Connection)
      Closed connection to database 'EFCore.Test' on server 'localhost' (12ms).
dbug: 02/12/2022 12:04:23.106 RelationalEventId.CommandCreating[20103] (Microsoft.EntityFrameworkCore.Database.Command)
      Creating DbCommand for 'ExecuteScalar'.
dbug: 02/12/2022 12:04:23.107 RelationalEventId.CommandCreated[20104] (Microsoft.EntityFrameworkCore.Database.Command)
      Created DbCommand for 'ExecuteScalar' (1ms).
dbug: 02/12/2022 12:04:23.108 RelationalEventId.CommandInitialized[20106] (Microsoft.EntityFrameworkCore.Database.Command)
      Initialized DbCommand for 'ExecuteScalar' (2ms).
dbug: 02/12/2022 12:04:23.109 RelationalEventId.ConnectionOpening[20000] (Microsoft.EntityFrameworkCore.Database.Connection)
      Opening connection to database 'EFCore.Test' on server 'localhost'.
dbug: 02/12/2022 12:04:23.111 RelationalEventId.ConnectionOpened[20001] (Microsoft.EntityFrameworkCore.Database.Connection)
      Opened connection to database 'EFCore.Test' on server 'localhost'.
dbug: 02/12/2022 12:04:23.112 RelationalEventId.CommandExecuting[20100] (Microsoft.EntityFrameworkCore.Database.Command)
      Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30']

      IF EXISTS
          (SELECT *
           FROM [sys].[objects] o
           WHERE [o].[type] = 'U'
           AND [o].[is_ms_shipped] = 0
           AND NOT EXISTS (SELECT *
               FROM [sys].[extended_properties] AS [ep]
               WHERE [ep].[major_id] = [o].[object_id]
                   AND [ep].[minor_id] = 0
                   AND [ep].[class] = 1
                   AND [ep].[name] = N'microsoft_database_tools_support'
          )
      )
      SELECT 1 ELSE SELECT 0
info: 02/12/2022 12:04:23.164 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (52ms) [Parameters=[], CommandType='Text', CommandTimeout='30']

      IF EXISTS
          (SELECT *
           FROM [sys].[objects] o
           WHERE [o].[type] = 'U'
           AND [o].[is_ms_shipped] = 0
           AND NOT EXISTS (SELECT *
               FROM [sys].[extended_properties] AS [ep]
               WHERE [ep].[major_id] = [o].[object_id]
                   AND [ep].[minor_id] = 0
                   AND [ep].[class] = 1
                   AND [ep].[name] = N'microsoft_database_tools_support'
          )
      )
      SELECT 1 ELSE SELECT 0
dbug: 02/12/2022 12:04:23.166 RelationalEventId.ConnectionClosing[20002] (Microsoft.EntityFrameworkCore.Database.Connection)
      Closing connection to database 'EFCore.Test' on server 'localhost'.
dbug: 02/12/2022 12:04:23.167 RelationalEventId.ConnectionClosed[20003] (Microsoft.EntityFrameworkCore.Database.Connection)
      Closed connection to database 'EFCore.Test' on server 'localhost' (0ms).
dbug: 02/12/2022 12:04:23.263 CoreEventId.StartedTracking[10806] (Microsoft.EntityFrameworkCore.ChangeTracking)
      Context 'MyContext' started tracking 'Request' entity with key '{RequestGuid: 301d0e77-8c9d-40c3-91cc-a9b6fddff08c}'.
dbug: 02/12/2022 12:04:23.266 CoreEventId.SaveChangesStarting[10004] (Microsoft.EntityFrameworkCore.Update)
      SaveChanges starting for 'MyContext'.
dbug: 02/12/2022 12:04:23.269 CoreEventId.DetectChangesStarting[10800] (Microsoft.EntityFrameworkCore.ChangeTracking)
      DetectChanges starting for 'MyContext'.
dbug: 02/12/2022 12:04:23.281 CoreEventId.DetectChangesCompleted[10801] (Microsoft.EntityFrameworkCore.ChangeTracking)
      DetectChanges completed for 'MyContext'.
dbug: 02/12/2022 12:04:23.344 RelationalEventId.ConnectionOpening[20000] (Microsoft.EntityFrameworkCore.Database.Connection)
      Opening connection to database 'EFCore.Test' on server 'localhost'.
dbug: 02/12/2022 12:04:23.344 RelationalEventId.ConnectionOpened[20001] (Microsoft.EntityFrameworkCore.Database.Connection)
      Opened connection to database 'EFCore.Test' on server 'localhost'.
dbug: 02/12/2022 12:04:23.348 RelationalEventId.CommandCreating[20103] (Microsoft.EntityFrameworkCore.Database.Command)
      Creating DbCommand for 'ExecuteReader'.
dbug: 02/12/2022 12:04:23.348 RelationalEventId.CommandCreated[20104] (Microsoft.EntityFrameworkCore.Database.Command)
      Created DbCommand for 'ExecuteReader' (0ms).
dbug: 02/12/2022 12:04:23.353 RelationalEventId.CommandInitialized[20106] (Microsoft.EntityFrameworkCore.Database.Command)
      Initialized DbCommand for 'ExecuteReader' (5ms).
dbug: 02/12/2022 12:04:23.358 RelationalEventId.CommandExecuting[20100] (Microsoft.EntityFrameworkCore.Database.Command)
      Executing DbCommand [Parameters=[@p0='301d0e77-8c9d-40c3-91cc-a9b6fddff08c', @p1='0x' (Nullable = false) (Size = 8000), @p2='MyCompany' (Size = 4000), @p3='mymail@mail.com' (Size = 4000), @p4='2022-12-02T11:04:23.1682170Z', @p5='Request Name' (Size = 4000), @p6='My Site' (Size = 4000), @p7='anonymous' (Nullable = false) (Size = 4000)], CommandType='Text', CommandTimeout='30']
      SET IMPLICIT_TRANSACTIONS OFF;
      SET NOCOUNT ON;
      INSERT INTO [common].[Requests] ([RequestGuid], [Archive], [CompanyName], [Mail], [RequestDate], [RequestName], [SiteName], [UserId])
      OUTPUT INSERTED.[Id]
      VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7);
info: 02/12/2022 12:04:23.401 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (47ms) [Parameters=[@p0='301d0e77-8c9d-40c3-91cc-a9b6fddff08c', @p1='0x' (Nullable = false) (Size = 8000), @p2='MyCompany' (Size = 4000), @p3='mymail@mail.com' (Size = 4000), @p4='2022-12-02T11:04:23.1682170Z', @p5='Request Name' (Size = 4000), @p6='My Site' (Size = 4000), @p7='anonymous' (Nullable = false) (Size = 4000)], CommandType='Text', CommandTimeout='30']
      SET IMPLICIT_TRANSACTIONS OFF;
      SET NOCOUNT ON;
      INSERT INTO [common].[Requests] ([RequestGuid], [Archive], [CompanyName], [Mail], [RequestDate], [RequestName], [SiteName], [UserId])
      OUTPUT INSERTED.[Id]
      VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7);
dbug: 02/12/2022 12:04:23.423 RelationalEventId.DataReaderClosing[20301] (Microsoft.EntityFrameworkCore.Database.Command)
      Closing data reader to 'EFCore.Test' on server 'localhost'.
dbug: 02/12/2022 12:04:23.425 RelationalEventId.DataReaderDisposing[20300] (Microsoft.EntityFrameworkCore.Database.Command)
      A data reader for 'EFCore.Test' on server 'localhost' is being disposed after spending 17ms reading results.
dbug: 02/12/2022 12:04:23.426 RelationalEventId.ConnectionClosing[20002] (Microsoft.EntityFrameworkCore.Database.Connection)
      Closing connection to database 'EFCore.Test' on server 'localhost'.
dbug: 02/12/2022 12:04:23.426 RelationalEventId.ConnectionClosed[20003] (Microsoft.EntityFrameworkCore.Database.Connection)
      Closed connection to database 'EFCore.Test' on server 'localhost' (0ms).
dbug: 02/12/2022 12:04:23.435 CoreEventId.StateChanged[10807] (Microsoft.EntityFrameworkCore.ChangeTracking)
      The 'Request' entity with key '{RequestGuid: 301d0e77-8c9d-40c3-91cc-a9b6fddff08c}' tracked by 'MyContext' changed state from 'Added' to 'Unchanged'.
dbug: 02/12/2022 12:04:23.437 CoreEventId.SaveChangesCompleted[10005] (Microsoft.EntityFrameworkCore.Update)
      SaveChanges completed for 'MyContext' with 1 entities written to the database.
dbug: 02/12/2022 12:04:23.451 CoreEventId.ValueGenerated[10808] (Microsoft.EntityFrameworkCore.ChangeTracking)
      'MyContext' generated temporary value '-2147482647' for the property 'Id.ModuleVariantA'.
dbug: 02/12/2022 12:04:23.473 CoreEventId.StartedTracking[10806] (Microsoft.EntityFrameworkCore.ChangeTracking)
      Context 'MyContext' started tracking 'ModuleVariantA' entity with key '{Id: -2147482647}'.
dbug: 02/12/2022 12:04:23.492 CoreEventId.ValueGenerated[10808] (Microsoft.EntityFrameworkCore.ChangeTracking)
      'MyContext' generated temporary value '-2147482647' for the property 'Id.ModuleHostA'.
dbug: 02/12/2022 12:04:23.506 CoreEventId.ReferenceChangeDetected[10805] (Microsoft.EntityFrameworkCore.ChangeTracking)
      The navigation 'ModuleHost.Requests' for entity with key '{Id: -2147482647}' was detected as changed.
dbug: 02/12/2022 12:04:23.521 CoreEventId.ForeignKeyChangeDetected[10803] (Microsoft.EntityFrameworkCore.ChangeTracking)
      The foreign key property 'ModuleBase.ModuleHostId' was detected as changed from '0' to '-2147482647' for entity with key '{Id: -2147482647}'.
dbug: 02/12/2022 12:04:23.527 CoreEventId.StartedTracking[10806] (Microsoft.EntityFrameworkCore.ChangeTracking)
      Context 'MyContext' started tracking 'ModuleHostA' entity with key '{Id: -2147482647}'.
dbug: 02/12/2022 12:04:23.528 CoreEventId.SaveChangesStarting[10004] (Microsoft.EntityFrameworkCore.Update)
      SaveChanges starting for 'MyContext'.
dbug: 02/12/2022 12:04:23.528 CoreEventId.DetectChangesStarting[10800] (Microsoft.EntityFrameworkCore.ChangeTracking)
      DetectChanges starting for 'MyContext'.
dbug: 02/12/2022 12:04:23.534 CoreEventId.DetectChangesCompleted[10801] (Microsoft.EntityFrameworkCore.ChangeTracking)
      DetectChanges completed for 'MyContext'.
dbug: 02/12/2022 12:04:23.549 RelationalEventId.BatchReadyForExecution[20700] (Microsoft.EntityFrameworkCore.Update)
      Executing 2 update commands as a batch.
dbug: 02/12/2022 12:04:23.550 RelationalEventId.ConnectionOpening[20000] (Microsoft.EntityFrameworkCore.Database.Connection)
      Opening connection to database 'EFCore.Test' on server 'localhost'.
dbug: 02/12/2022 12:04:23.550 RelationalEventId.ConnectionOpened[20001] (Microsoft.EntityFrameworkCore.Database.Connection)
      Opened connection to database 'EFCore.Test' on server 'localhost'.
dbug: 02/12/2022 12:04:23.553 RelationalEventId.TransactionStarting[20209] (Microsoft.EntityFrameworkCore.Database.Transaction)
      Beginning transaction with isolation level 'Unspecified'.
dbug: 02/12/2022 12:04:23.561 RelationalEventId.TransactionStarted[20200] (Microsoft.EntityFrameworkCore.Database.Transaction)
      Began transaction with isolation level 'ReadCommitted'.
dbug: 02/12/2022 12:04:23.563 RelationalEventId.CommandCreating[20103] (Microsoft.EntityFrameworkCore.Database.Command)
      Creating DbCommand for 'ExecuteReader'.
dbug: 02/12/2022 12:04:23.563 RelationalEventId.CommandCreated[20104] (Microsoft.EntityFrameworkCore.Database.Command)
      Created DbCommand for 'ExecuteReader' (0ms).
dbug: 02/12/2022 12:04:23.565 RelationalEventId.CommandInitialized[20106] (Microsoft.EntityFrameworkCore.Database.Command)
      Initialized DbCommand for 'ExecuteReader' (2ms).
dbug: 02/12/2022 12:04:23.565 RelationalEventId.CommandExecuting[20100] (Microsoft.EntityFrameworkCore.Database.Command)
      Executing DbCommand [Parameters=[@p0='VariantA' (Nullable = false) (Size = 4000), @p1='301d0e77-8c9d-40c3-91cc-a9b6fddff08c', @p2='-2147482647', @p3='ModuleIdentifier' (Size = 4000), @p4=NULL (DbType = Double)], CommandType='Text', CommandTimeout='30']
      SET NOCOUNT ON;
      INSERT INTO [common].[ModuleHost] ([ModuleHostTypeName], [ReadingRequestGuid])
      OUTPUT INSERTED.[Id]
      VALUES (@p0, @p1);
      INSERT INTO [iq4].[ModuleVariant] ([ModuleHostId], [ModuleIdentifier], [ValueField])
      OUTPUT INSERTED.[Id]
      VALUES (@p2, @p3, @p4);
info: 02/12/2022 12:04:23.578 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (13ms) [Parameters=[@p0='VariantA' (Nullable = false) (Size = 4000), @p1='301d0e77-8c9d-40c3-91cc-a9b6fddff08c', @p2='-2147482647', @p3='ModuleIdentifier' (Size = 4000), @p4=NULL (DbType = Double)], CommandType='Text', CommandTimeout='30']
      SET NOCOUNT ON;
      INSERT INTO [common].[ModuleHost] ([ModuleHostTypeName], [ReadingRequestGuid])
      OUTPUT INSERTED.[Id]
      VALUES (@p0, @p1);
      INSERT INTO [iq4].[ModuleVariant] ([ModuleHostId], [ModuleIdentifier], [ValueField])
      OUTPUT INSERTED.[Id]
      VALUES (@p2, @p3, @p4);
dbug: 02/12/2022 12:04:23.611 CoreEventId.ForeignKeyChangeDetected[10803] (Microsoft.EntityFrameworkCore.ChangeTracking)
      The foreign key property 'ModuleHost.Id' was detected as changed from '-2147482647' to '3' for entity with key '{Id: 3}'.
dbug: 02/12/2022 12:04:23.616 CoreEventId.ForeignKeyChangeDetected[10803] (Microsoft.EntityFrameworkCore.ChangeTracking)
      The foreign key property 'ModuleBase.ModuleHostId' was detected as changed from '-2147482647' to '3' for entity with key '{Id: -2147482647}'.
dbug: 02/12/2022 12:04:23.704 RelationalEventId.DataReaderClosing[20301] (Microsoft.EntityFrameworkCore.Database.Command)
      Closing data reader to 'EFCore.Test' on server 'localhost'.
dbug: 02/12/2022 12:04:23.705 RelationalEventId.DataReaderDisposing[20300] (Microsoft.EntityFrameworkCore.Database.Command)
      A data reader for 'EFCore.Test' on server 'localhost' is being disposed after spending 95ms reading results.
dbug: 02/12/2022 12:04:23.734 RelationalEventId.TransactionDisposed[20204] (Microsoft.EntityFrameworkCore.Database.Transaction)
      Disposing transaction.
dbug: 02/12/2022 12:04:23.735 RelationalEventId.ConnectionClosing[20002] (Microsoft.EntityFrameworkCore.Database.Connection)
      Closing connection to database 'EFCore.Test' on server 'localhost'.
dbug: 02/12/2022 12:04:23.735 RelationalEventId.ConnectionClosed[20003] (Microsoft.EntityFrameworkCore.Database.Connection)
      Closed connection to database 'EFCore.Test' on server 'localhost' (0ms).
fail: 02/12/2022 12:04:23.790 CoreEventId.SaveChangesFailed[10000] (Microsoft.EntityFrameworkCore.Update)
      An exception occurred in the database while saving changes for context type 'MyContext'.
      Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
       ---> Microsoft.Data.SqlClient.SqlException (0x80131904): The INSERT statement conflicted with the FOREIGN KEY constraint "FK_ModuleVariant_ModuleHost_ModuleHostId". The conflict occurred in database "EFCore.Test", table "common.ModuleHost", column 'Id'.
         at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
         at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
         at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
         at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
         at Microsoft.Data.SqlClient.SqlDataReader.TryHasMoreRows(Boolean& moreRows)
         at Microsoft.Data.SqlClient.SqlDataReader.TryReadInternal(Boolean setTimeout, Boolean& more)
         at Microsoft.Data.SqlClient.SqlDataReader.Read()
         at Microsoft.EntityFrameworkCore.Storage.RelationalDataReader.Read()
         at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeResultSet(Int32 startCommandIndex, RelationalDataReader reader)
         at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.Consume(RelationalDataReader reader)
      ClientConnectionId:deb1faa9-8465-4556-b3da-3187a5aca85c
      Error Number:547,State:0,Class:16
         --- End of inner exception stack trace ---
         at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.Consume(RelationalDataReader reader)
         at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
         at Microsoft.EntityFrameworkCore.SqlServer.Update.Internal.SqlServerModificationCommandBatch.Execute(IRelationalConnection connection)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable`1 commandBatches, IRelationalConnection connection)
         at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChanges(IList`1 entries)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IList`1 entriesToSave)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(StateManager stateManager, Boolean acceptAllChangesOnSuccess)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.<>c.<SaveChanges>b__107_0(DbContext _, ValueTuple`2 t)
         at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
         at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)

Include provider and version information

EF Core version: 7.0.0
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: net7.0
Operating system: 10.0.19042
IDE: Visual studio 2022 17.4.1

@ajcvickers
Copy link
Member

/cc @roji Still fails on latest daily.

@roji
Copy link
Member

roji commented Dec 3, 2022

This seems to be a TPC-related metadata bug... We have both ModuleVariantA and ModuleVariantB (TPC hierarchy) referencing ModuleHost (TPH hierarchy). However, looking at the ReferencingForeignKeyConstraints for ModuleHost's table, I can see one foreign key constraint from iq2 (ModuleVariantB), but the other one from iq4 (ModuleVariableA) is missing. This causes the topological sort to not add a foreign key edge, which causes both INSERTs to be executed in the same batch, causing the exception.

@AndriySvyryd, I think you'll want to take it from here...

Here's a simplified single-file repro, including the metadata lookup:

var ctx = GetContext();

var relationalModel = ctx.Model.GetRelationalModel();
var table = relationalModel.FindTable("ModuleHost", "common");
foreach (var foreignKeyConstraint in table.ReferencingForeignKeyConstraints)
{
    // Should show two constraints, shows one.
    Console.WriteLine(foreignKeyConstraint.Table);
}

var address = new ModuleVariantA // <= The child
{
    ModuleIdentifier = "ModuleIdentifier",
    ModuleHost = new ModuleHostA // <= The Parent
    {
        Modules = new List<ModuleVariantA>() { },
    }
};

ctx.Attach(address);
ctx.SaveChanges();

Console.ReadLine();

static MyContext GetContext()
{
    var factory = new MyContextFactory();

    var ctx = factory.CreateDbContext(Array.Empty<string>());

    // ctx.Database.EnsureDeleted();
    // ctx.Database.EnsureCreated();

    return ctx;
}

public class MyContextFactory : IDesignTimeDbContextFactory<MyContext>
{
    public MyContext CreateDbContext(string[] args)
    {
        // var connectionString = "User Id=XX;Password=XX;TrustServerCertificate=True;data source=localhost;initial catalog=EFCore.Test;MultipleActiveResultSets=True;App=EntityFramework";
        var connectionString = "Server=localhost;Database=test;User=SA;Password=Abcd5678;Connect Timeout=60;ConnectRetryCount=0;Encrypt=false";
        var options = new DbContextOptionsBuilder<MyContext>()
                   .UseSqlServer(connectionString, x => x.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery))
                   .LogTo(Console.WriteLine, LogLevel.Information)
                   .EnableSensitiveDataLogging()
                   .Options;

        return new MyContext(options);
    }
}

public class MyContext : DbContext
{
    public DbSet<ModuleHost> ModuleHosts { get; set; } = default!;
    public MyContext(DbContextOptions<MyContext> options) : base(options)
    {
    }

    protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
    {
        configurationBuilder
            .Properties<TimeSpan>()
            .HaveConversion<string>();

        base.ConfigureConventions(configurationBuilder);
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasDefaultSchema("common");

        modelBuilder.Entity<ModuleHost>(x =>
        {
            x.Ignore(x => x.ModuleHostType);
            x.UseTphMappingStrategy();
            x.HasDiscriminator(x => x.ModuleHostTypeName)
                .HasValue<ModuleHostC>(ModuleHostType.VariantB.ToString())
                .HasValue<ModuleHostA>(ModuleHostType.VariantA.ToString())
                .HasValue<ModuleHostB>(ModuleHostType.VariantC.ToString())
                .HasValue<UnknownModuleHost>(ModuleHostType.None.ToString())
                .IsComplete(false);

            x.HasKey(x => x.Id);
            x.Property(x => x.Id).UseIdentityColumn();
        });

        modelBuilder.Entity<ModuleBase>().UseTpcMappingStrategy();
        modelBuilder.Entity<ModuleVariantBase>().UseTpcMappingStrategy();
        modelBuilder.Entity<ModuleVariantA>()
            .HasOne(x => x.ModuleHost as ModuleHostA)
            .WithMany(x => x.Modules)
            .IsRequired()
            .HasForeignKey(x => x.ModuleHostId);

        modelBuilder.Entity<ModuleVariantB>()
            .HasOne(x => x.ModuleHost as ModuleHostC)
            .WithMany(x => x.ModuleVariantBs)
            .IsRequired()
            .HasForeignKey(x => x.ModuleHostId);


        base.OnModelCreating(modelBuilder);
    }
}

public abstract record class ModuleBase
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; init; }
    public ModuleHost ModuleHost { get; set; }
    public int ModuleHostId { get; set; }
    public string? ModuleIdentifier { get; init; }
}

[Table("ModuleHost", Schema = "common")]
public class ModuleHost
{
    [Key]
    public int Id { get; init; }
    // public Request Requests { get; set; }
    // public Guid ReadingRequestGuid { get; set; }

    public virtual ModuleHostType ModuleHostType { get; set; }
    public string ModuleHostTypeName
    {
        set => ModuleHostType = (ModuleHostType)Enum.Parse(typeof(ModuleHostType), value, true);
        get => ModuleHostType.ToString();
    }
}
public class ModuleHostA : ModuleHost
{
    public override ModuleHostType ModuleHostType { get => ModuleHostType.VariantA; }
    public virtual ICollection<ModuleVariantA> Modules { get; init; } = new List<ModuleVariantA>();
}
public class ModuleHostB : ModuleHostA
{
    public override ModuleHostType ModuleHostType { get => ModuleHostType.VariantA; }
}
public class ModuleHostC : ModuleHost
{
    public override ModuleHostType ModuleHostType { get => ModuleHostType.VariantC; }
    public virtual ICollection<ModuleVariantB> ModuleVariantBs { get; init; } = new List<ModuleVariantB>();
}
public class UnknownModuleHost : ModuleHost
{

}

[Flags]
public enum ModuleHostType
{
    None = 0,
    VariantBB = 0b0000_0001 | VariantB,
    VariantB = 0b0000_1000,
    VariantA = 0b0001_0000,
    VariantC = 0b0010_0000,
}

public abstract record class ModuleVariantBase : ModuleBase
{
    public double? ValueField { get; init; }
}

[Table("ModuleVariant", Schema = "iq4")]
public record class ModuleVariantA : ModuleVariantBase
{
    public double? ValueField { get; init; }
}

[Table("ModuleVariant", Schema = "iq2")]
public record class ModuleVariantB : ModuleVariantBase
{
    public double? RemoteLan { get; init; }
    public double? AlarmAdress { get; init; }
    public double? TextOnOff { get; init; }
    public string? SupplyFrequency { get; init; }
    public string? ReferenceVolts { get; init; }
}

@AlexandreRevel
Copy link
Author

Any temporary workaround idea?

@ajcvickers ajcvickers removed this from the 8.0.0 milestone Jan 3, 2023
@ajcvickers
Copy link
Member

/cc @AndriySvyryd

@AndriySvyryd
Copy link
Member

There isn't a reasonable workaround I can come up with

@ajcvickers
Copy link
Member

@AndriySvyryd Should we patch then?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-model-building closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported Servicing-approved type-bug
Projects
None yet
Development

No branches or pull requests

4 participants