kwv84 kwv84 - 2 months ago 10
C# Question

Override DbContext EF6

I'm trying to understand how to dynamically create the connection string for my DbContext, but my application says it has no connection string in the app.config (and that's correct because I don't want to use it in the app.config or web.config). This is what I have:

In my solution I have a project called InterfaceApp. It is a ASP.NET MVC 5 application. When I put my connection string in the web.config all seems to be working fine.

In my solution I have an other project called InterfaceApp.Connector.Erp1. Here I want to connect to an ERP application and fetch some items. So in my repository I have:

namespace InterfaceApp.Connector.Erp1.Repository
{
internal class ItemRepository : IItemRepository
{
public IEnumerable<Item> Items
{
get
{
List<Item> items = new List<Item>();

using (Models.Entities context = new Models.Entities())
{
var itemList = context.Items.ToList();
foreach(var item in itemList)
{
items.Add(new Item() { Id = item.ID, Description = item.Description, ItemCode = item.ItemCode });
}
}

return items.ToList();
}
}
}
}


I've created a partial class to connect to the database:

namespace InterfaceApp.Connector.Erp1.Models
{
public partial class Entities
{
public Entities(string connectionString)
: base(ConnectionString())
{
}


private static string ConnectionString()
{
SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder
{
DataSource = "MyServer", //When this works it will be dynamic
InitialCatalog = "XXX", //When this works it will be dynamic
PersistSecurityInfo = true,
IntegratedSecurity = true,
MultipleActiveResultSets = true,

};

var entityConnectionStringBuilder = new EntityConnectionStringBuilder
{
Provider = "System.Data.SqlClient",
Metadata = "res://*/Models.Erp1Model.csdl|res://*/Models.Erp1Model.ssdl|res://*/Erp1Model.msl",
ProviderConnectionString = sqlBuilder.ConnectionString

};

return entityConnectionStringBuilder.ConnectionString;

}
}
}


The Context class that is auto-generated by EF6 (Db First) looks like this:

namespace InterfaceApp.Connector.Erp1.Models
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;

public partial class Entities : DbContext
{
public Entities()
: base("name=Entities")
{
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}

public virtual DbSet<Items> Items { get; set; }
}
}


When I run my application, the debugger stops at the auto-generated class, but not at my partial class. Because it cannot find the connection string
Entities
in my app.config and web.config it generates an error saying that the connection string is not found in the application config file. What am I doing wrong?

Answer

When you are calling the DbContext, you're calling the empty constructor (new Models.Entities()). Thus, it will call the auto-generated DbContext. If you want to call your partial class, you need to call it explicitly with the parameter.

Remember when you create a partial class, the compiler merges them, so you have this when compiled :

public partial class Entities : DbContext
{
    public Entities()
        : base("name=Entities")
    {
    }
    public Entities(string connectionString)
        : base(ConnectionString())
    {
    }


    private static string ConnectionString()
    {
        SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder
        {
            DataSource = "MyServer", //When this works it will be dynamic
            InitialCatalog = "XXX", //When this works it will be dynamic
            PersistSecurityInfo = true,
            IntegratedSecurity = true,
            MultipleActiveResultSets = true,

        };

        var entityConnectionStringBuilder = new EntityConnectionStringBuilder
        {
            Provider = "System.Data.SqlClient",
            Metadata = "res://*/Models.Erp1Model.csdl|res://*/Models.Erp1Model.ssdl|res://*/Erp1Model.msl",
            ProviderConnectionString = sqlBuilder.ConnectionString

        };

        return entityConnectionStringBuilder.ConnectionString;

    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }

    public virtual DbSet<Items> Items { get; set; }
}

What you probably need a a method to create your DbContext and call it instead of calling a new DbContext.

public static Entities Create()
{
    return new Entities(ConnectionString());
}

Then you can use it this way :

using (var context = Entities.Create())
{
     //...
}
Comments