Подтвердить что ты не робот

Entity Framework: изменение строки подключения во время выполнения

Предполагая, что есть приложение ASP.NET MVC, которое использует Entity Framework 6 с кодовым подходом и StructureMap как IoC.
Кроме того, он использует шаблон Unit Of Work. Вот коды:

Класс домена

    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }        
 
    }

IUnitOfWork и DbContext:

    public interface IUnitOfWork
{
    IDbSet<TEntity> Set<TEntity>() where TEntity : class;
    int SaveChanges();
}

public class Sample07Context : DbContext, IUnitOfWork
{
    public DbSet<Product> Products { set; get; }

    #region IUnitOfWork Members

    public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
    {
        return base.Set<TEntity>();
    }

    #endregion
}

Бизнес-логика в классах обслуживания:

   public interface IProductService
{
    void AddNewProduct(Product product);
    IList<Product> GetAllProducts();
}


    public class ProductService : IProductService
    {
        IUnitOfWork _uow;
        IDbSet<Product> _products;
        public ProductService(IUnitOfWork uow)
        {
            _uow = uow;
            _products = _uow.Set<Product>();
        }
 
        public void AddNewProduct(Product product)
        {
            _products.Add(product);
        }
 
        public IList<Product> GetAllProducts()
        {
            return _products.Include(x => x.Category).ToList();
        }
    }

Ввод класса обслуживания в контроллер

        public class HomeController : Controller
    {
        private IProductService _productService;
        private IUnitOfWork _uow;

        public HomeController(IUnitOfWork uow, IProductService productService)
        {
            _productService = productService;

            _uow = uow;
        }

        [HttpGet]
        public ActionResult Index()
        {
            var list = _productService.GetAllProducts();
            return View(list);
        }
    }

Конфигурация StructureMap, которую мы вызываем в app_start:

       private static void initStructureMap()
        {
            ObjectFactory.Initialize(x =>
            {
                x.For<IUnitOfWork>().HttpContextScoped().Use(() => new Sample07Context());
                x.ForRequestedType<IProductService>().TheDefaultIsConcreteType<EfProductService>();
            });
            //Set current Controller factory as StructureMapControllerFactory
            ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
        }

Все работает отлично с единой базой данных, но в моем сценарии пользователь может использовать несколько баз данных, я имею в виду, что пользователь должен иметь возможность изменять строку соединения во время выполнения. Мы создаем отдельную базу данных для каждого проекта, созданного пользователем в приложении.
Теперь проблема заключается в том, что мы добавляем DbContext для обслуживания, а DbContext считывает строку подключения из web.config, поэтому, когда пользователь меняет базу данных, мы не можем установить новую строку подключения для DbContext.
Что вы предлагаете?

4b9b3361

Ответ 1

По моему опыту, я использовал режим Database First в EF 6. DbContext будет генерироваться, как показано ниже, когда я добавляю Entity Data Model.

public TestEntities()
            : base("name=TestEntities")
        {
        }

TestEntities представляет элемент ConnectionString в App.Config

<connectionStrings>   
<add name="TestEntities" connectionString="..." providerName="System.Data.EntityClient" />
</connectionStrings>

Но вы можете изменить код по умолчанию ниже.

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

        public TestEntities(string sConnectionString)
            : base(sConnectionString)
        {
        }

...}

Итак, у вас есть два варианта подключения к DB.

  • используя значение по умолчанию. EF найдет строку подключения в файле конфигурации.

  • передача строки подключения в DbContext.

Код выглядит следующим образом.

EntityConnection entityConn =DBConnectionHelper.BuildConnection();
using (var db = new TestEntities(entityConn.ConnectionString))
{
....
}

Что касается вопроса How to build a EntityConnection?. См. MSDN EntityConnection.

Надеюсь, это полезно.

Спасибо.

Ответ 2

По умолчанию имя строки подключения для использования в Entity Framework выводится из имени вашего класса DbContext. Однако вы можете передать строку подключения в качестве параметра конструктора:

public class MyDbContext : DbContext, IUnitOfWork
{
    public MyDbContext(string connectionString)
        : base(connectionString)
    {
    }
}

Затем вы можете настроить StructureMap для передачи в текущей строке соединения, например.

For<IUnitOfWork>().Use(ctx => new MyDbContext(TheConnectionStringToUse));

Это может исходить от статического значения, которое вы задали в своем коде, текущем сеансе и т.д.

Ответ 3

Я собираюсь предложить совершенно другой путь. Предполагая, что у вас есть строки подключения, установленные в вашем web.config, что вы говорите, почему бы вам не использовать web.debug.config и web.release.config transforrms, чтобы правильно установить строки подключения?

то есть. в web.debug.config

<connectionStrings>
    <add name="FooEntities" connectionString="metadata=res://*/;provider=System.Data.SqlClient;provider connection string="Data Source=IP,PORT\Instancename;
    Initial Catalog=Foo;Persist Security Info=True;User ID=admin;Password=password;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient"/>
</connectionStrings>

и web.release.config как таковой

<connectionStrings xdt:Transform="Replace">
    <add name="FooEntities" connectionString="metadata=res://*/;provider=System.Data.SqlClient;provider connection string="Data Source=LIVEIP,PORT\Instancename;
    Initial Catalog=Foo;Persist Security Info=True;User ID=admin;Password=password;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient"/>
</connectionStrings>

Существует очень подробное объяснение здесь

Ответ 4

 public partial class YourDBContextClass
 {
    // Add a constructor to allow the connection string name to be changed
 public YourDBContextClass(string connectionStringNameInConfig)
        : base("name=" + connectionStringNameInConfig)
    {
    }
}

Добавьте несколько строк подключения в свой веб файл или файл app.config.

в вашем программном коде:

YourDBContextClass dbcontext = new YourDBContextClass("alternateconnectionstringname");

Ответ 5

Два подхода хороши для двух разных ситуаций:

  • Преобразование полезно для развертывания строки подключения, которая изменяется только для разных версий (тест, производство).

  • Подход добавления конструктора (который принимает имя строки подключения) в отдельном файле для расширения частичного класса dbcontext позволяет переключать соединение во время выполнения.

Ответ 6

Добавьте две разные строки подключения в файл App.Config, используя другое имя.

Установить текущее имя строки подключения в конструкторе Entity с помощью перегрузки.

  

В файле кода

public ASM_DBEntities()
        : base("name=ASM_DBEntities")
    {
    }

    public ASM_DBEntities(string conn)
        : base("name=ASM_DBEntities1")
    {

    }

Когда мы передаем строку с объектом, используется другая строка соединения.