Coder Social home page Coder Social logo

Comments (8)

crhairr avatar crhairr commented on June 7, 2024 1

Yeah, there was a bug that I noticed right after I posted my last comment. It should be fixed now, and there's a new package out there. My apologies for that.

This might be a limitation of EF Core in general. After doing a little bit of research, it appears that the IModel instances are cached as singletons based on the DbContext type. If you place a breakpoint in your OnModelCreating, you'll probably find that it's only being called once per process, despite multiples instantiations.

EF Core assumes a 1:1 relationship between a DbContext and a particular database, and EFCore-MongoDb doesn't behave any differently. I assume that users will create a different DbContext class for each specific named MongoDB database instance with which they want to communicate.

Since you're creating an ETL process, you could also create two derived DbContext types as for example SourceDbContext and the TargetDbContext and set the appropriate database names in each context's OnModelCreating method. That would be a cleaner approach from a coding perspective, as it would give a contextual usage to each DbContext.

If you really need to dynamically set the database, you can add a property or extension method on your DbContext:

    public string Database
    {
        get => Model.MongoDb().Database;
        set => Model.MongoDb().Database = value;
    }

However, this is not a supported use and I'm not sure how it would affect the runtime.

from entityframeworkcore.

crhairr avatar crhairr commented on June 7, 2024 1

To clarify my last comment, the IModel instances aren't cached per process. They're cached per service container. Each time you new up an IServiceCollection and register EF Core or EFCore-MongoDb dependencies, you'll get a fresh instance of the model. However, building the model is a very expensive process that involves heavy use of reflection, so this is not something that should be done dynamically.

So if this is, for example, part of a web application, you should in theory only build the model once per application startup. In that scenario, trying to change the model's database will have serious consequences, and could result in unintended data leaking not only from the source to the target (or vice versa depending on how you're setting the database name) but also between different sets of source and target databases.

If you really, absolutely need to be able to set truly dynamic database names, then your best bet will be to wrap up your ETL related DbContexts into an isolated service container that is instantiated and populated on demand by the parent application. In this scenario, it still would be wisest to have separate Source and Target contexts that are derived from the same abstract base context. This way, you'll ensure that you won't run into any issues with unintended data leaking between the source and target, and especially between different sets of source and target databases.

from entityframeworkcore.

crhairr avatar crhairr commented on June 7, 2024

The database attribute convention sets a model annotation. You can find the annotations here, which can be used from OnModelCreating like this:

public void OnModelCreating(ModelBuilder modelBuilder)
{
    var annotations = modelBuilder.MongoDb();
    annotations.Database = "DatabaseName";
    //apply other settings
}

There's also a convenience method that you can use:

public void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.ForMongoDbFromDatabase("DatabaseName");
}

from entityframeworkcore.

crhairr avatar crhairr commented on June 7, 2024

As for the connection string: I do not parse it, I just pass it directly to the MongoDB C# driver. A single mongo db connection can open an arbitrary number of databases, so the database name in the connection string is largely ignored. The driver only uses the /database portion as a reference to the database that contains authentication information if the connection string contains credentials. The only time this is different is when the db is "admin", which is used to access db admin commands such as shutting down the database (see the unit tests).

I would prefer not to change the semantics of what a MongoDb connection string means. So for now, please use the attribute or model annotation.

from entityframeworkcore.

dannotsys avatar dannotsys commented on June 7, 2024

Sorry Chris, my mistake about the connection string. About the approach using Annotations on OnModelCreating, I have already tried that, but EF seems to cache the database name among the model info and I was unable to change anymore, once setted. It is there some way to change it at anytime (more than once) like calling GetDatabase() on the c# driver?

from entityframeworkcore.

crhairr avatar crhairr commented on June 7, 2024

Two things..,

  1. I forgot about a third option for setting the database, which is in MongoDbContextOptionsBuilder and can be used when setting up the db context:
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseMongoDb(
            "mongodb://localhost",
            options => options.UseDatabase("Database"));
    }
  1. Are you also setting the [Database] attribute on the db context class? The convention for interpreting this attribute is an IModelBuiltConvention which is run after the rest of the model has been finalized, after both OnConfiguring and OnModelCreating have been called, which means that the attribute can override anything you're setting in those methods. Please make sure that you're not setting the attribute if you're trying to use direct configuration.

from entityframeworkcore.

dannotsys avatar dannotsys commented on June 7, 2024

I have tried the MongoDbContextOptionsBuilder.UseDatabase approach but seems not to be working at all, the database ended up created with my DbContext class name (ContextMongoDb : DbContext). Subsequent instantiateds DbContexts (on the same process) keeped using this database name.

I am not using the Database attribute.

from entityframeworkcore.

dannotsys avatar dannotsys commented on June 7, 2024

Sorry for the late feedback, worked flawless as you have pointed out.

I have created a new instance of Microsoft.Extensions.DependencyInjection.ServiceCollection on a facade class that receives a delegate (Func<IServiceCollection, IServiceCollection>) (for multi provider support) where I have pointed to MongoDbEfServiceCollectionExtensions.AddEntityFrameworkMongoDb. I have also overriden the OnConfiguring method like below from a parent abstract DbContext class for automatically set the new serviceProvider (created on my facade class too using the new serviceCollection)

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);

            optionsBuilder
                .UseInternalServiceProvider(myCustomServiceProvider);
        }

I needed this ability to change the Database at runtime for the same Entity Model due the multi tenancy requirements of my project.

from entityframeworkcore.

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.