0

In my project I do have many Database Contexts.

1. MyContext1 
2. MyContext2 
3. MyContext3 

I am currently using database first approach (edmx based).

As part of edmx creation all these contexts are created. I would like to disable lazy loading for all these contexts.

I thought of writing a partial class for this. So for each Context there will be a partial class and which is responsible for disabling the lazy loading.

My current approach is something like below

[DbConfigurationType(typeof(InterceptorConfiguration))]
    public partial class MyContext1 : DbContext
    {
        public static MyContext1 Create()
        {
            var applicationDbContext = new MyContext1();
            applicationDbContext.Configuration.LazyLoadingEnabled = false;
            return applicationDbContext;
        }
    }

Here i do have static method where i manually create instance of context and apply the configurations and returning it. Is there any other way to do this without creating a direct instance in the partial class?

Since there is already a default constructor in the edmx auto generated class I cannot write a constructor in the partial class which I have created.

I can disable this one in service layer, but since this one is an existing project I dont want to touch everywhere. So is there any better solution to do the same ?

Since this one is an existing application and it has many edmx files I cannot edit/change anything in the edmx including t4 template

Arunprasanth K V
  • 20,733
  • 8
  • 41
  • 71
  • Does this answer your question? [Override or replace default constructor when using database first approach](https://stackoverflow.com/questions/35070584/override-or-replace-default-constructor-when-using-database-first-approach) – Johnathan Barclay Jul 24 '20 at 12:36
  • @JohnathanBarclay sorry not exactly. This needs changing the existing edmx t4 template. And this will change most of my existing classes also(edmx related) I am not allowed to change this. Else i could have added it in the service layer itself – Arunprasanth K V Jul 24 '20 at 13:13
  • Use a context factory. – Gert Arnold Jul 24 '20 at 13:37
  • @GertArnold I am using Simple Injector and i do have Db context provider which is responsible for providing the instance as scoped. It act like a factory where i can get the instance based on need, But the issue is its a generic type and the simple injector GetInstance method return object , so i cannot get DbContext type there and do this operations – Arunprasanth K V Jul 24 '20 at 13:43
  • Then give the partial contexts constructors in which you can inject an options object that directs the lazy-loading option. – Gert Arnold Jul 24 '20 at 13:47
  • @GertArnold I ddint complexly get the point you mentioned, can u explain it little more ? – Arunprasanth K V Jul 24 '20 at 13:49

1 Answers1

0

Finally got a solution.

Since I am using Simple Injector Dependency Injection package in my solution. I have created a provider for getting the instance at run time.

public sealed class DbContextProvider<T> : IDbContextProvider<T>
     where T : DbContext
{
    /// <summary>
    /// The producer
    /// </summary>
    private readonly InstanceProducer producer;

    /// <summary>
    /// Initializes a new instance of the <see cref="DbContextProvider{T}"/> class.
    /// </summary>
    /// <param name="container">The container.</param>
    /// <exception cref="InvalidOperationException">You forgot to register {typeof(T).Name}. Please call: " +
    ///                     $"container.Register<{typeof(T).Name}>(Lifestyle.Scope);</exception>
    public DbContextProvider(Container container)
    {
        this.producer = container.GetCurrentRegistrations()
            .FirstOrDefault(r => r.ServiceType == typeof(T))
            ?? throw new InvalidOperationException(
                $"You forgot to register {typeof(T).Name}. Please call: " +
                $"container.Register<{typeof(T).Name}>(Lifestyle.Scope);");
    }

    /// <summary>
    /// Gets the context.
    /// </summary>
    /// <value>
    /// The context.
    /// </value>
    public T Context
    {
        get
        {
            DbContext dbContext = (T)this.producer.GetInstance();
            //Dynamic proxies are used for change tracking and lazy loading
            //if DbContext.Configuration.ProxyCreationEnabled is set to false, DbContext will not load child objects 
            //for some parent object unless Include method is called on parent object.
            dbContext.Configuration.ProxyCreationEnabled = false;
            return (T)dbContext;
        }
    }
}

Then the interface

 public interface IDbContextProvider<out T> where T : DbContext
    {
        /// <summary>
        /// Gets the context.
        /// </summary>
        /// <value>
        /// The context.
        /// </value>
        T Context { get; }
    }

I can call this one from service layer like

private readonly IDbContextProvider<MyDbContext> _baseContextProvider;

public MyService(IDbContextProvider<MyDbContext> baseContextProvider)
        {
            this._baseContextProvider = baseContextProvider;
        }
Arunprasanth K V
  • 20,733
  • 8
  • 41
  • 71