Coder Social home page Coder Social logo

Comments (18)

rowanmiller avatar rowanmiller commented on June 15, 2024 1

@funzeye this is all changing in the upcoming RC2 and IdentityDbContext will have a constructor that allows you to pass in all this stuff.

from entityframework.docs.

logamanig avatar logamanig commented on June 15, 2024 1

Following code works perfectly for me,
// Requires separate DI Service provider to isolate db instance as InMemory database is also shared within
// the class scope since the App Service Factory is configured to per scope instance for dbcontext
var internalServiceProviderForDbContext = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
var options = new DbContextOptionsBuilder()
.UseInternalServiceProvider(internalServiceProviderForDbContext)
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
.Options;

As pointed out by @ajcvickers , internal service provider is not required. specifying the inMemoryRoot in optionbuilder is the best way to do it.

from entityframework.docs.

rowanmiller avatar rowanmiller commented on June 15, 2024

Should also cover this point that was mentioned in #105

Keep DbContext's isolated; don't re-use the same context to seed the database and then query.

from entityframework.docs.

VeronicaWasson avatar VeronicaWasson commented on June 15, 2024

I'm trying to write a test that uses two DbContext's, sharing the same in-memory DB. The idea is to create the entities using the first context, and pass a clean context to the code that I'm testing. That way I can validate that I'm loading navigation properties correctly, etc, in my EF7 code. The best I could find was to register my DbContext as a transient:

public class TestClass
{
    private readonly ServiceCollection _serviceCollection;
    private readonly DbContextOptions<MyDbContext> _options;

    public TestClass()
    {
        var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>();
        optionsBuilder.UseInMemoryDatabase();
        _options = optionsBuilder.Options;

        var _serviceCollection = new ServiceCollection();
        _serviceCollection
            .AddEntityFramework()
            .AddInMemoryDatabase();

        _serviceCollection.AddTransient<MyDbContext>(provider => new MyDbContext(provider, _options));
    }

    [Fact]
    public Test1()
    {
        IServiceProvider provider = _serviceCollection.BuildServiceProvider();
        using (var context = provider.GetService<MyDbContext>())
        {
            context.Add(new Thing { Id = 1 });
            context.SaveChanges();
        }

        using (var context = provider.GetService<ApplicationDbContext>())
        {
            // test with a new context but same DB
        }
    }
}

It seems to work, but is there a better way to achieve this?

from entityframework.docs.

rowanmiller avatar rowanmiller commented on June 15, 2024

@MikeWasson it's a bit of a "level up" on DI skills... but you can create scopes within a service provider to get new instances of scoped services... but the non-scoped services (such as the InMemory store) are shared between all scopes on the provider.

This actually emulates nicely what happens in ASP.NET - where a new scope is created for each request. So Test1() now approximates some data being inserted on one request and then some other logic happening on a second request that accesses the same database.

public class TestClass
{
    private readonly ServiceCollection _serviceCollection;

    public TestClass()
    {
        _serviceCollection = new ServiceCollection();
        _serviceCollection
            .AddEntityFramework()
            .AddInMemoryDatabase()
            .AddDbContext<SampleContext>(c => c.UseInMemoryDatabase());
    }

    [Fact]
    public Test1()
    {
        IServiceProvider provider = _serviceCollection.BuildServiceProvider();
        using (var scope = provider.GetRequiredService<IServiceScopeFactory>().CreateScope())
        {
            var context = scope.ServiceProvider.GetService<MyDbContext>())
            context.Add(new Thing { Id = 1 });
            context.SaveChanges();
        }

        using (var scope = provider.GetRequiredService<IServiceScopeFactory>().CreateScope())
        {
            var context = scope.ServiceProvider.GetService<MyDbContext>())
            // test with a new context but same DB
        }
    }
}

from entityframework.docs.

rowanmiller avatar rowanmiller commented on June 15, 2024

Page is now available at http://docs.efproject.net/en/latest/miscellaneous/testing.html

@MikeWasson I came up with some patterns to make things a little simpler (though we still have plenty of room for improvement - mostly implementing dotnet/efcore#3253) so you should take a look at the final article.

from entityframework.docs.

Abrissirba avatar Abrissirba commented on June 15, 2024

Awesome Rowan! :) That was exactly what I needed to understand how to scope my contexts :)

from entityframework.docs.

chenlonghu avatar chenlonghu commented on June 15, 2024

@rowanmiller Thanks Rowan. Your doc was helpful !

from entityframework.docs.

funzeye avatar funzeye commented on June 15, 2024

inheriting from IdentityDbContext throws a bit of spanner in the works with this: (http://docs.efproject.net/en/latest/miscellaneous/testing.html) - it doesnt contain a constructor that takes two arguments

from entityframework.docs.

funzeye avatar funzeye commented on June 15, 2024

cool,
great work guys. EF FTW.

from entityframework.docs.

mgallig avatar mgallig commented on June 15, 2024

@rowanmiller Hi. I reported this a while ago and since then the named dbcontext can be passed in but -- I find that the context is still shared.

I probably use a weird edge-case, but I am performing a bunch of integration tests in xunit (which work better than I could have ever hoped, with the exception of this problem) that spins up a TestServer with UseInMemoryDatabase for each test class.

The problem is, even with separate test servers, with separate dbcontexts, the underlying in memory database was still shared (each was created with a new Guid for a name)

I also get a "A second operation on this context....." type error that I'll never see in actual production all the time due to apparent context sharing.

from entityframework.docs.

ajcvickers avatar ajcvickers commented on June 15, 2024

@mgallig Please file a new issue on https://github.com/aspnet/EntityFramework including a full code listing or project that will let us reproduce what you are seeing.

from entityframework.docs.

babu12f avatar babu12f commented on June 15, 2024

where is ServiceCollection class

from entityframework.docs.

ajcvickers avatar ajcvickers commented on June 15, 2024

@babu12f https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicecollection?view=aspnetcore-2.1

from entityframework.docs.

logamanig avatar logamanig commented on June 15, 2024

Following code works perfectly for me,
// Requires separate DI Service provider to isolate db instance as InMemory database is also shared within
// the class scope since the App Service Factory is configured to per scope instance for dbcontext
var internalServiceProviderForDbContext = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
var options = new DbContextOptionsBuilder()
.UseInternalServiceProvider(internalServiceProviderForDbContext)
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
.Options;

from entityframework.docs.

ajcvickers avatar ajcvickers commented on June 15, 2024

@logamanig It's generally best to avoid calling UseInternalServiceProvider if you don't really need to.

from entityframework.docs.

logamanig avatar logamanig commented on June 15, 2024

@logamanig It's generally best to avoid calling UseInternalServiceProvider if you don't really need to.

without calling UseInternalServiceProvider, not able to isolate the InMemoryDatabase instance between test cases. Just a unique database name is not enough to isolate.

from entityframework.docs.

ajcvickers avatar ajcvickers commented on June 15, 2024

See dotnet/efcore#3253 (comment)

from entityframework.docs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.