Entity Framework Core 1.1 Nel database di memoria non riesce ad aggiungere nuove entità

entity-framework-core

Domanda

Sto usando il seguente codice in un test unitario per l'impostazione del test:

var simpleEntity = new SimpleEntity();
var complexEntity = new ComplexEntity
{
    JoinEntity1List = new List<JoinEntity1>
    {
        new JoinEntity1
        {
            JoinEntity2List = new List<JoinEntity2>
            {
                new JoinEntity2
                {
                    SimpleEntity = simpleEntity
                }
            }
        }
    }
};
var anotherEntity = new AnotherEntity
{
    ComplexEntity = complexEntity1
};

using (var context = databaseFixture.GetContext())
{
    context.Add(anotherEntity);
    await context.SaveChangesAsync();
}

Quando viene raggiunto SaveChangesAsync EF genera una ArgumentException con il seguente messaggio:

Un articolo con la stessa chiave è già stato aggiunto. Chiave: 1

Sto usando una fixture anche per la classe di test unitario che popola il database con oggetti dello stesso tipo, anche se per questo test voglio questa particolare configurazione quindi voglio aggiungere queste nuove entità al database in memoria. Ho provato ad aggiungere le entità su DbSet (non su DbContext) e ad aggiungere tutte e tre le entità separatamente senza alcun risultato. Posso comunque aggiungere "simpleEntity" separatamente (perché non è aggiunto alla fixture) ma EF si lamenta non appena provo ad aggiungere "complexEntity" o "anotherEntity".

Sembra che l'EF nel database della memoria non possa gestire diversi Add da diverse istanze del contesto. C'è qualche soluzione per questo o sto facendo qualcosa di sbagliato nel mio setup?

Il databaseFixture in questo caso è un'istanza di questa classe:

namespace Test.Shared.Fixture
{
    using Data.Access;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.Extensions.DependencyInjection;

    public class InMemoryDatabaseFixture : IDatabaseFixture
    {
        private readonly DbContextOptions<MyContext> contextOptions;

        public InMemoryDatabaseFixture()
        {
            var serviceProvider = new ServiceCollection()
            .AddEntityFrameworkInMemoryDatabase()
            .BuildServiceProvider();

            var builder = new DbContextOptionsBuilder<MyContext>();
            builder.UseInMemoryDatabase()
                   .UseInternalServiceProvider(serviceProvider);

            contextOptions = builder.Options;
        }

        public MyContext GetContext()
        {
            return new MyContext(contextOptions);
        }
    }
}

Risposta popolare

È possibile risolvere questo problema utilizzando le Fixtures Collection in modo da poter condividere questo dispositivo su diverse classi di test. In questo modo non crei il tuo contesto più volte e quindi non otterrai questa eccezione:

Alcune informazioni sulla collezione Fixture

Il mio esempio:

[CollectionDefinition("Database collection")]
public class DatabaseCollection : ICollectionFixture<DatabaseFixture>
{  }

[Collection("Database collection")]
public class GetCitiesCmdHandlerTests : IClassFixture<MapperFixture>
{
    private readonly TecCoreDbContext _context;
    private readonly IMapper _mapper;

    public GetCitiesCmdHandlerTests(DatabaseFixture dbFixture, MapperFixture mapFixture)
    {
        _context = dbFixture.Context;
        _mapper = mapFixture.Mapper;
    }

    [Theory]
    [MemberData(nameof(HandleTestData))]
    public async void Handle_ShouldReturnCountries_AccordingToRequest(
        GetCitiesCommand command,
        int expectedCount)
    {
        (...)
    }

    public static readonly IEnumerable<object[]> HandleTestData
        = new List<object[]>
        {
            (...)
        };
}

}

Buona fortuna, Seb



Related

Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché