如何在 Entity Framework 6 中保存复杂对象

问题描述 投票:0回答:1

我正在为 C# / SQL Server 应用程序编写单元测试。 MS 建议在不使用生产数据库进行测试时使用 SQLite (https://learn.microsoft.com/en-us/ef/core/testing/testing-without-the-database#inmemory-provider)。我有 SQLite 设置,我正在尝试用测试数据填充数据库。我将生产数据示例导出为 JSON 格式,并将其与测试项目一起保存,这样我就可以相当轻松地更新测试数据。设置 SQLite 上下文的代码是我从 MS 文章中获取的。

除了这个块之外没有行号可供参考

var memoryData = new ReqestDataInMemory();
var data = memoryData.AllRepositoryRequests();

这会获取 json 并以

IEnumerable
的形式返回复杂的对象结构。然后我尝试将其保存到
DbContext
:

public class TestDbContext
{
    public SqliteConnection _connection {get; set;} 
    public DbContextOptions<TaxonomyContext> _contextOptions { get; set;}

    public TestDbContext()
    {
        // Create and open a connection. This creates the SQLite in-memory database, which will persist until the connection is closed
        // at the end of the test (see Dispose below).
        _connection = new SqliteConnection("Filename=:memory:");
        _connection.Open();

        // These options will be used by the context instances in this test suite, including the connection opened above.
        _contextOptions = new DbContextOptionsBuilder<TaxonomyContext>()
            .UseSqlite(_connection)
            .Options;

        // Create the schema and seed some data
        using var context = new TaxonomyContext(_contextOptions);

        if (context.Database.EnsureCreated())
        {
            using var viewCommand = context.Database.GetDbConnection().CreateCommand();
            viewCommand.CommandText = @"
                CREATE VIEW AllRequests AS
                SELECT Url
                FROM Request";
            viewCommand.ExecuteNonQuery();
        }

        var memoryData = new ReqestDataInMemory();
        var data = memoryData.AllRepositoryRequests();

        context.AddRange(data);
        context.SaveChanges();
    }
}

AddRange()
抛出错误

System.InvalidOperationException:无法跟踪实体类型“RequestType”的实例,因为已跟踪具有相同键值 {'RequestTypeId'} 的另一个实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。

如果它试图一遍又一遍地保存查找表,这是有道理的。这就是我的问题。

这是我正在使用的对象。

RequestType
是我遇到拦截器的地方,它是一个简单的查找表
RequestType.Id and RequestType.Name
Status
是一对多查找表。所有人都有 FK 关系回到
Request

ChangeDetail
对象是有关请求的详细信息。它具有唯一的 ID 和请求的 FK。

我尝试将

RequestType
Statuses
都置为 NULL,但它

public class Request
{
    public int RequestId { get; set; }
    /// <summary>changed from "navarchar(max)" to "text" for sqlite testing db </summary>
    [Required]
    [MinLength(50)]
    [Column(TypeName = "text")]
    public string Justification { get; set; } = string.Empty;
    [Required]
    public int SubmitUser { get; set; }
    [Required]
    public DateTime SubmitDate { get; set; }
    public int? ModifyUser { get; set; }
    public DateTime? ModifyDate { get; set; }
    public virtual IEnumerable<ChangeDetail> ChangeDetail { get; set; } = new List<ChangeDetail>();
    public virtual IEnumerable<Status> Statuses { get; set; } = new List<Status>();
    public virtual RequestType RequestType { get; set; } = new RequestType();
}

我的查询效果很好,所以我认为我所有的关系都是稳固的。以防万一有帮助,以下是关系。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Request>()
            .HasOne(x => x.RequestType)
            .WithMany(x => x.Requests);

    modelBuilder.Entity<Request>()
            .HasMany(x => x.ChangeDetail)
            .WithOne(x => x.Request);

    modelBuilder.Entity<Request>()
            .HasMany(x => x.Statuses)
            .WithMany(x => x.Requests);

    modelBuilder.Entity<Status>()
            .HasOne(x => x.RequestStatusType)
            .WithMany(x => x.Statuses);
}

为了解决这个问题,我尝试了以下方法: LINQ 查询从对象列表中返回不同的字段值

我认为这显示出希望,使用 Entity.Unmodified 但无法让它工作 在实体框架 6 中保存分离实体

这谈论的是 FK,我已经设置了它,但也许它在保存时没有引用它们?

如何阻止实体框架尝试保存/插入子对象?

我感谢您提出的任何建议。

c# sqlite unit-testing entity-framework-core .net-6.0
1个回答
0
投票

我想我会结束这个循环。我花了一段时间,但这是多对多关系的连接表之一中的数据问题。一旦我修复了

© www.soinside.com 2019 - 2024. All rights reserved.