动态使用DbContext

时间:2016-07-06 13:03:05

标签: sql-server entity-framework asp.net-web-api dbcontext

我有多个具有相同架构的数据库。 在我的代码中,我想通过参数查询其中一个DB,该参数会动态更改。

现在它看起来像这样:

public void saveNewUser(User user, string type)
{
        if (type == "A")
        {
            using (var db = new AEntities())
            {
                db.Users.Add(user);
                db.SaveChanges();
            }
        }
        else
        {

            using (var db = new BEntities())
            {
                db.Users.Add(user);
                db.SaveChanges();
            }
        }

 }

相反,我想做这样的事情:

public void saveNewUser(User user, string type)
{
        using (var db = new GeneralEntity(type))
        {
            db.Users.Add(user);
            db.SaveChanges();
        }
}

有什么好主意吗?

4 个答案:

答案 0 :(得分:1)

根据我的经验,我只有一个DbContext来解决类似的问题。我只是在运行时修改连接字符串。实体框架通过允许您使用连接字符串调用构造函数来支持此功能。

我允许管理员将设置作为配置文件进行维护,对于给定的模型,应用程序将其存储为加密SQL设置的集合。在运行时,此列表作为字典加载,其中配置文件名称(“A”,“B”)用作键。

然后使用需要连接字符串的DbContext构造函数,并根据目标db传递一个构建的连接字符串:

// the model name in the app.config connection string (any model name - Model1?)
private string BuildConnectionString(string profile)
{
    // configuration would hold the collection of settings - however you prefer to provide this
    var settings = configuration.GetConnectionSettings(profile);
    // Build the provider connection string with configurable settings
    var providerSB = new SqlConnectionStringBuilder
    {
        InitialCatalog = settings.InitialCatalog,
        DataSource = settings.DataSource,
        UserID = settings.User,
        Password = settings.Password
    };    
    var efConnection = new EntityConnectionStringBuilder();
    // or the config file based connection without provider connection string
    // var efConnection = new EntityConnectionStringBuilder(@"metadata=res://*/model1.csdl|res://*/model1.ssdl|res://*/model1.msl;provider=System.Data.SqlClient;");
    efConnection.Provider = "System.Data.SqlClient";
    efConnection.ProviderConnectionString = providerSB.ConnectionString;
    // based on whether you choose to supply the app.config connection string to the constructor
    efConnection.Metadata = "res://*/Model.DbEntities.csdl|res://*/Model.DbEntities.ssdl|res://*/Model.DbEntities.msl", model;
    return efConnection.ToString();

}

然后在您的示例中,您将只使用一个DbContext:

using (var db = new DbEntities(BuildConnectionString("A")))
{
    db.Users.Add(user);
    db.SaveChanges();
}

答案 1 :(得分:0)

可能会使用类似工厂类的东西吗?

public void saveNewUser(User user, string type)
{
        using (var db = myclass.GetGeneralEntity(type))
        {
            db.Users.Add(user);
            db.SaveChanges();
        }
}

答案 2 :(得分:0)

DbContext方法Set<TEntity>返回通用DbSet<TEntity>。您可以使用此而不是添加的属性来覆盖DbContext,即。在您的调用代码中引用基类DbContext,它不关心DbContext的实际实例是什么。

public class MyClass  {
    private DbContext _context;
    public MyClass(DbContext context){
        _context = context;
    }

    public void saveNewUser(User user)
    {
        _context.Set<User>.Add(user);
        _context.SaveChanges();
    }
}

上面的示例依赖于DI在构造函数中获取正确的DbContext实例,只要它稍后知道实体User时就不关心哪个具体实现调用方法saveNewUser(否则将抛出异常)。 DI框架还可以处理处理创建的DbContext,或者您可以实现IDisposableMyClass并在处置方法中处置DbContext。或者,您可以注入DbContext工厂以在需要时创建一个工厂。 (有很多选项,只取决于您的首选框架,可能还有您的应用目前的结构)。

假设

我认为你的意思是实际的底层实体是完全相同的类型。如果这是错误的并且还有许多User类型,那么这将无效。

答案 3 :(得分:0)

我在寻找的是如何动态返回AEntity / BEntity,对象已经存在。

我所做的是:

 protected override void OnStart()
        {            
            if (WCHSBMobileApplication.Current.SuperBillObject == null)
            {
                AddSuperBill();
            }
            else
            {
                EditSuperBill();
            }
        }

为了动态接收类型:

public class DbContextGeneral : DbContext
{
    public virtual Users;
}

public class AEntity : DbContextGeneral
{
    public override Users;
}
public class BEntity : DbContextGeneral
{
    public override Users;
}

然后,最后:

private DbContextGeneral GetDBInstance(string value)
{
    if (value == "A")
    {
        return new AEntity();
    }
    return new BEntity();
}