简体   繁体   English

SQLite 单元测试中的 FOREIGN KEY 约束失败

[英]FOREIGN KEY constraint failed in SQLite unit tests

I have a database with two different paths to a certain entity, one path with DeleteBehavior.Cascade and the other with DeleteBehavior.Restrict to avoid a multiple cascade paths error on database creation.我有两个不同的路径,以一定的实体,一个路径数据库DeleteBehavior.Cascade和其他与DeleteBehavior.Restrict避免数据库创建多个级联路径错误。 This is working as I expected when running locally using IIS Express and Visual Studio's SQL Server in memory, but throwing an error in unit tests testing the same functionality.当在内存中使用 IIS Express 和 Visual Studio 的 SQL Server 在本地运行时,这正如我预期的那样工作,但在测试相同功能的单元测试中抛出错误。

Example:例子:

public class Account
{
    public string Id { get; set; }
}

Each account can have subscriptions:每个帐户都可以订阅:

public class Subscription
{
    public string Id { get; set; }

    // relationships

    public string AccountId { get; set; }

    public Account Account { get; set; }
}

Both accounts and subscriptions can have contacts (this might not make much sense but it's just an example, in reality my model is more complicated but it essentially boils down to this):帐户和订阅都可以有联系人(这可能没有多大意义,但这只是一个例子,实际上我的模型更复杂,但基本上归结为这个):

public class Contact
{
    public string Id { get; set; }

    // relationships

    public string AccountId { get; set; }

    public Account Account { get; set; }

    public string SubscriptionId { get; set; }

    public Subscription Subscription { get; set; }
}

I want any contacts to be deleted if either the account or the subscription is deleted.如果帐户或订阅被删除,我希望删除任何联系人。 This is my model builder config for contacts:这是我的联系人模型构建器配置:

public void Configure(EntityTypeBuilder<Contact> entity)
{
    entity.HasOne(e => e.Account)
        .WithMany()
        .HasForeignKey(e => e.AccountId)
        .OnDelete(DeleteBehavior.Restrict);

    entity.HasOne(e => e.Subscription)
        .WithMany()
        .HasForeignKey(e => e.SubscriptionId)
        .OnDelete(DeleteBehavior.Cascade);
}

config for subscriptions:订阅配置:

public void Configure(EntityTypeBuilder<Subscription> entity)
{
    entity.HasOne(e => e.Account)
        .WithMany()
        .HasForeignKey(e => e.AccountId)
        .OnDelete(DeleteBehavior.Cascade);
}

The thought being that when an account is deleted this will delete the subscriptions via the Cascade delete behavior, and this will delete the contacts, with the Restrict behavior between accounts and contacts solving the "multiple cascade paths" error.这个想法是,当一个帐户被删除时,这将通过Cascade删除行为删除订阅,这将删除联系人,帐户和联系人之间的Restrict行为解决了“多级联路径”错误。

This works when I'm running locally, I can delete an account and all subscriptions and contacts are deleted, no error.这在我本地运行时有效,我可以删除一个帐户并删除所有订阅和联系人,没有错误。 The issue is in the unit tests (using xUnit), which are using SQLite in memory.问题在于单元测试(使用 xUnit),它在内存中使用 SQLite。 I want to test that deleting an account will delete all contacts:我想测试删除帐户会删除所有联系人:

[Fact]
public async Task DeleteAccount_ContactIsDeleted()
{
    using (var factory = new ContextFactory()) // same connection will be used within using block
    {
        using (var context = factory.CreateContext())
        {
            await context.SeedDatabaseOneContactAsync(); // inserts account, subscription and contact into database
        }

        using (var context = factory.CreateContext())
        {
            Assert.Single(context.Contacts);
            Assert.Single(context.Subscriptions);
            Assert.Single(context.Accounts);

            var account = await context.Accounts.SingleAsync();
            context.Remove(account);
            await context.SaveChangesAsync();

            Assert.Empty(context.Contacts);
            Assert.Empty(context.Accounts);
            Assert.Empty(context.Subscriptions);
        }
    }
}

However this throws the following error但是,这会引发以下错误

Message: Microsoft.EntityFrameworkCore.DbUpdateException : An error occurred while updating the entries.消息:Microsoft.EntityFrameworkCore.DbUpdateException:更新条目时出错。 See the inner exception for details.有关详细信息,请参阅内部异常。 ---- Microsoft.Data.Sqlite.SqliteException : SQLite Error 19: 'FOREIGN KEY constraint failed'. ---- Microsoft.Data.Sqlite.SqliteException:SQLite 错误 19:“外键约束失败”。

on the line在线上

await context.SaveChangesAsync();

I'd like to know if this is an issue with SQLite, or if there's something I'm doing wrong with my model or config?我想知道这是否是 SQLite 的问题,或者我的模型或配置是否有问题?

Note: I'm using Entity Framework Core 2.1.1, and these relationships are required (can't be nullable).注意:我使用的是 Entity Framework Core 2.1.1,并且这些关系是必需的(不能为空)。

By default, FK contstraints are disabled in SQLite.默认情况下,SQLite 中禁用 FK 约束。 http://www.sqlite.org/foreignkeys.html http://www.sqlite.org/foreignkeys.html

Foreign key constraints are disabled by default (for backwards compatibility), so must be enabled separately for each database connection.默认情况下禁用外键约束(为了向后兼容),因此必须为每个数据库连接单独启用。 (Note, however, that future releases of SQLite might change so that foreign key constraints enabled by default. Careful developers will not make any assumptions about whether or not foreign keys are enabled by default but will instead enable or disable them as necessary.) (但是请注意,SQLite 的未来版本可能会更改,以便默认启用外键约束。细心的开发人员不会对默认情况下是否启用外键做出任何假设,而是会根据需要启用或禁用它们。)

You can enable them with by adding foreign keys=true to your connection string.您可以通过在连接字符串中添加foreign keys=true来启用它们。 ( data source=test.db;foreign keys=true for a full example) data source=test.db;foreign keys=true完整示例)

Not sure if this is your problem but, I had the same error when the fluent API relationship config did not match the actual table structure.不确定这是否是您的问题,但是,当流畅的 API 关系配置与实际表结构不匹配时,我遇到了同样的错误。

In my case the fluent API setup a one to one relationship but the actual underlying table structure was a one to many relationship.在我的例子中,流畅的 API 设置了一对一的关系,但实际的底层表结构是一对多的关系。

Old question but I'm having this same issue.老问题,但我有同样的问题。

So far I think it's related to the column being a string which you can't set as a nullable value type.到目前为止,我认为它与作为字符串的列有关,您不能将其设置为可空值类型。 eg.例如。 string?细绳? if you change it to Guid?如果你把它改成 Guid? or int?或int? then you don't have the same issue.那么你没有同样的问题。

I think this might be a bug in entity framework where it thinks the column is not nullable when it actually is.我认为这可能是实体框架中的一个错误,它认为该列实际上是不可为空的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM