Как правильно выгрузить connection string c xml файла в DBContext

114
30 сентября 2021, 19:30

Есть база данных, созданная на основе CodeFirst EntityFramework.

Я создал класс для сохранения данных Connection String'a и методы сохранения и выгрузки данных

public class ConnectionString
    {        
        public string DataSource { get; set; }
        public string InitialCatalog { get; set; }
        public string UserId { get; set; }
        public string Password { get; set; }
        public ConnectionString() { }
        public ConnectionString(string dataSource, string initialCatalog, string userId, string password)
        {
            DataSource = dataSource;
            InitialCatalog = initialCatalog;
            UserId = userId;
            Password = password;
        }
        public override string ToString()
        {
            return $"Data Source={DataSource};Initial Catalog={InitialCatalog};User Id={UserId};Password={Password}";
        }
        public ConnectionString LoadFile(string path)
        {
            try
            {
                ConnectionString result;
                XmlSerializer formatter = new XmlSerializer(typeof(ConnectionString));
                using (var fs = new FileStream("DataConnection.xml", FileMode.Open))
                {
                    result = (ConnectionString)formatter.Deserialize(fs);
                }
                return result;
            }
            catch
            {
                throw new Exception("File not uploaded!");
            }
        }
        public void SaveFile(object obj, string path)
        {
            try
            {
                XmlSerializer formatter = new XmlSerializer(obj.GetType());
                using (var fs = new FileStream("DataConnection.xml", FileMode.OpenOrCreate))
                {
                    formatter.Serialize(fs, obj);
                }
            }
            catch
            {
                throw new Exception("File not saved!");
            }
        }
    }

Есть класс представляющий таблицу в базе данных

public class User
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public int Age { get; set; }
    }

И класс принимающий DbContext

public class UserContext : DbContext
    {
        ConnectionString cs;
        public UserContext() : base("DbConnection")
        { }
        public UserContext(string connect) : base(connect)
        {
            try
            {
                cs = new ConnectionString();
                var loadData = cs.LoadFile("DataConnection.xml");
                string connString = String.Format("Data Source={0};Initial Catalog={1};User Id={2};Password={3}", loadData.DataSource, loadData.InitialCatalog, loadData.UserId, loadData.Password);
                using (SqlConnection conn = new SqlConnection(connString))
                {
                    conn.Open();
                    MessageBox.Show("Connect!");
                }               
            }
            catch
            {
                MessageBox.Show("No connection!");
            }              
        }
        public DbSet<User> Users { get; set; }
    }

Так заполнял данными когда изначально создал код и базу данных

public void CreateData()          
 {
        using (db = new UserContext())
        {
            User user1 = new User { FirstName = "Eugene", Age = 28 };
            User user2 = new User { FirstName = "Serhiy", Age = 32 };
            db.Users.Add(user1);
            db.Users.Add(user2);
            db.SaveChanges();
        }
    }

Вопрос вот в чем, если я захочу поменять базу данных, пересоздам файл с нужным подключением. Как мне с файла правильно вытянуть эту строку и передать в DbContext?

Answer 1

В качестве просто идеи, как это можно реализовать.

Например, у нас есть контекст (просто его эмуляция для примера)

public class DbContext : IDisposable
{
    public void Dispose() {}
    public DbContext(string str)
    {
        Console.WriteLine($"dc is using {str}");
    }
}

Я накидал нехитрый класс для хранния конфига

public class ConnectionStringSource
{
    private string _filename;
    private Dictionary<string,string> _conStrings = new Dictionary<string,string>();
    private string _selected;
    public ConnectionStringSource(string filename) =>   
        _filename = filename;

    public void Load()
    {
        using(var sr = new StreamReader(_filename))
        {
            var ser = new XmlSerializer(typeof(ConnectionStringSourceSettings));
            var settings = (ConnectionStringSourceSettings)ser.Deserialize(sr);
            _conStrings = settings.ConnectionStrings.ToDictionary(x=>x.name, x=>x.connString);
            _selected = settings.Selected;
        }
    }
    public void Save()
    {
        using (var sw = new StreamWriter(_filename))
        {
            var ser = new XmlSerializer(typeof(ConnectionStringSourceSettings));
            var settings = new ConnectionStringSourceSettings()
            {
                ConnectionStrings = _conStrings.Select(x =>(name : x.Key, connString:x.Value)).ToList(),
                Selected = _selected
            };
            ser.Serialize(sw, settings);
        }
    }
    public void Add(string name, string connectionString)=> 
        _conStrings[name] = connectionString;

    public void SetActive(string name){
        if (_conStrings.ContainsKey(name))
            _selected = name;
        else throw new ArgumentException(nameof(name));
    }
    public string GetSelectedConnectionString() =>  
        _conStrings[_selected];

    public class ConnectionStringSourceSettings
    {       
        public List<(string name, string connString)> ConnectionStrings { get; set; } = new List<(string, string)>();       
        public string Selected { get; set; }
    }
}

Тогда мы можем в реальном времени кидать в конфиг новые строки, созранять его, загружать его, и т.д.

var source = new ConnectionStringSource(@"D:\temp\SampleConfig.xml");
source.Add("string1", "my_connection_string");
source.SetActive("string1");

using(var dc = new DbContext(source.GetSelectedConnectionString()))
{
    // .....
}

source.Add("string2", "my_connection_string_2");
source.SetActive("string2");
using (var dc = new DbContext(source.GetSelectedConnectionString()))
{
    // .....
}
source.SetActive("string1");
using (var dc = new DbContext(source.GetSelectedConnectionString()))
{
    // .....
}
source.Save();

В выводе увидим, что в разное время контексты данных будут получать разные строки

dc is using my_connection_string
dc is using my_connection_string_2
dc is using my_connection_string

При этом контексту самому абсолютно не интересно, как там для него выбирается строка соединения.

READ ALSO
Как получить паку в которой лежит prefab?

Как получить паку в которой лежит prefab?

У меня есть виджет в EditorWindow который формирует список префабов:

98
Cтупенчатый массив и LINQ [закрыт]

Cтупенчатый массив и LINQ [закрыт]

Хотите улучшить этот вопрос? Обновите вопрос так, чтобы он вписывался в тематику Stack Overflow на русском

90
DialogResult.OK Не работает. WPF C#

DialogResult.OK Не работает. WPF C#

Почему то выдает ошибку:

114