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

Mirosoft.Data.Sqlite 7.0, SQLite Error 19: 'FOREIGN KEY constraint failed' #30081

Closed
Eruka opened this issue Jan 17, 2023 · 5 comments
Closed

Comments

@Eruka
Copy link

Eruka commented Jan 17, 2023

Hi, I have a many-to-many relation between entities and it worked well in EF Core 6. After update to EF Core 7 main app also works as expected but the integration tests which use inmemory Sqlite fail with exception SQLite Error 19: 'FOREIGN KEY constraint failed'.
Also in logs I can see next exception:

System.InvalidOperationException : The relationship from 'CompanyPlanSubscription.Company' to 'Company.CompanyPlanSubscriptions' with foreign key properties {'CompanyId' : int} cannot target the primary key {'Id' : Guid} because it is not compatible. Configure a principal key or a set of foreign key properties with compatible types for this relationship.

Relationships are defined in the configuration for company (EntityTypeBuilder builder):

  builder.HasAlternateKey(e => e.CompanyId);

  builder.HasMany(comp => comp.CompanyPlans)
                .WithMany(plan => plan.Companies)
                .UsingEntity<CompanyPlanSubscription>(
                    x => x.HasOne(sub => sub.CompanyPlan)
                            .WithMany(plan => plan.CompanyPlanSubscriptions)
                            .HasForeignKey(sub => sub.CompanyPlanId)
                            .OnDelete(DeleteBehavior.NoAction),
                    x => x.HasOne(sub => sub.Company)
                            .WithMany(comp => comp.CompanyPlanSubscriptions)
                            .HasForeignKey(sub => sub.CompanyId)
                            .HasPrincipalKey(comp => comp.CompanyId)
                            .OnDelete(DeleteBehavior.NoAction)
                    x => x.HasKey(t => new { t.CompanyId, t.CompanyPlanId });

public class Company
    {
        [Key]
        public Guid Id { get; set; }
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int CompanyId { get; set; }
        // .....
        public IList<CompanyPlanSubscription> CompanyPlanSubscriptions { get; set; } = new List<CompanyPlanSubscription>();
        public IList<CompanyPlan> CompanyPlans { get; set; } = new List<CompanyPlan>();
}

public class CompanyPlan
    {
        [Key]
        public CompanyPlanId Id { get; set; }        
        public IList<CompanyPlanSubscription> CompanyPlanSubscriptions { get; set; } = new List<CompanyPlanSubscription>();
        public IList<Company> Companies { get; set; } = new List<Company>();
    }

 public class CompanyPlanSubscription
    {
        public int CompanyId { get; set; }
        public CompanyPlanId CompanyPlanId { get; set; }
        public Company Company { get; set; }
        public CompanyPlan CompanyPlan { get; set; }
    }

Company creation in a tests class looks like:

var customer = new Company()
                {
                    CompanyPlanSubscriptions = new List<CompanyPlanSubscription>()
                    {
                        new CompanyPlanSubscription()
                        {
                            CompanyPlanId = CompanyPlanId.Customer,
                        },
                        new CompanyPlanSubscription()
                        {
                            CompanyPlanId = CompanyPlanId.Supplier,
                        },
                    },
                };
context.Add(customer);
context.SaveChanges();

Version information

Microsoft.Data.Sqlite version: 7.0.2
Target framework: .NET 7.0
Operating system: Windows 10

<PackageReference Include="Microsoft.Data.Sqlite" Version="7.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.2" />
@ajcvickers
Copy link
Contributor

This issue is lacking enough information for us to be able to fully understand what is happening. Please attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate.

@Eruka
Copy link
Author

Eruka commented Jan 18, 2023

SQLite.UpgradeToV7.zip

@ajcvickers
Here some example which works on ef core 6 and doesn't work after upgrading to v7

The code works if I use primary key to define many to many relationship, but it fails if I want to use alternate key.
HasPrincipal() doesn't work in v7 but works in v6

Thank you in advance

@ajcvickers
Copy link
Contributor

@bricelam Looks like CreateFunction may be broken here.

@ajcvickers
Copy link
Contributor

ajcvickers commented Jan 29, 2023

On further investigation, this seems to be related to the update pipeline changes in EF7. The code is dynamically creating a trigger. However, marking all tables with HasTrigger doesn't appear to change the code that the update pipeline generates.

/cc @roji

@ajcvickers
Copy link
Contributor

Notes for triage: verified that reverting to the old SQL generator fixes this. This means #29916 should cover this case. See also dotnet/EntityFramework.Docs#4241

@Eruka As a workaround, do something like this:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.ReplaceService<IUpdateSqlGenerator, SqliteLegacyUpdateSqlGenerator>();

@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Feb 16, 2023
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

3 participants