C # Как подключиться к различным базам данных на основе флага - PullRequest
0 голосов
/ 05 июня 2018

Я пытаюсь создать общую функцию в проекте C # Webapi для подключения к одной из двух баз данных на основе значения флага ввода.Каждая база данных имеет одинаковую структуру, но разные данные, и каждый вызов будет использовать одну и ту же базу данных повсюду.

Остальная часть моего кода не зависит от базы данных, поэтому он должен иметь возможность использовать общий объект БД, а неПринятие решения каждый раз, когда выполняется вызов в базу данных.

Вот код, который, как я думал, сработает:

public static dynamic GetDb(string scope = "dev") {
    dynamic db;

    if (Globals.db == null) {
        switch (scope.ToLower()) {
        case "tns":
            db = new TnsDb();
            break;

        case "sng":
            db = new SngDb();
            break;

        default:
            db = new TnsDb();
            break;
        }

        Globals.db = db;
    } else {
        db = Globals.db;
    }

    return db;
}

Я использую Entity Framework, которая создалакласс доступа для каждой базы данных, которую я подключил к проекту, и содержит метод для каждой хранимой процедуры, к которой мне нужно получить доступ.Я хотел бы, чтобы этот общий метод возвращал объект, представляющий соответствующий класс базы данных.

У меня проблема в том, что метод не возвращает пригодный для использования объект.Я попытался использовать тип возвращаемого динамического (как выше), простой объект и DbContext (родительский класс класса DB Entity Framework) и некоторые другие вещи из отчаяния, но каждый раз, когда вызывающий оператор получает обратно объекту которого нет ни одного из методов, присутствующих в классе базы данных Entity Framework.

Любые идеи о том, как динамически выбирать и возвращать соответствующий объект, сохраняющий все методы, будут с благодарностью приняты, поскольку я смогу сохранитьпо крайней мере, некоторые из моих волос.

Ответы [ 2 ]

0 голосов
/ 05 июня 2018

Успех!Я закончил тем, что создал интерфейс, который имел те же методы, что и класс db, и возвратил его из общего метода.

Вот фрагмент из интерфейса:

public interface IDatabase {
    ObjectResult<Method_1_Result> Method_1(Nullable<int> id, string username);
    ObjectResult<Method_2_Result> Method_2(string username, string password);
}

и вот эквивалентметоды из классов db:

public partial class TnsDb : DbContext, IDatabase {
    public TnsDbDev()
        : base("name=TnsDb")
    {
    }

    public virtual ObjectResult<Method_1_Result> Method_1(Nullable<int> id, string username)
    {
        return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<Method_1_Result>("Method_1", idParameter, usernameParameter);
    }

    public virtual ObjectResult<Method_2_Result> Method_2(string username, string password)
    {
        return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<Method_2_Result>("Method_2", usernameParameter, passwordParameter);

    }
}

public partial class SngDb : DbContext, IDatabase {
    public SngDbDev()
        : base("name=SngDb")
    {
    }

    public virtual ObjectResult<Method_1_Result> Method_1(Nullable<int> id, string username)
    {
        return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<Method_1_Result>("Method_1", idParameter, usernameParameter);
    }

    public virtual ObjectResult<Method_2_Result> Method_2(string username, string password)
    {
        return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<Method_2_Result>("Method_2", usernameParameter, passwordParameter);

    }
}

Обратите внимание, что мне пришлось удалить тела get и set из метода интерфейса, поскольку они не были нужны и продолжали генерировать ошибки.

Я такжеПодозреваю, что это решение является специфическим для моей ситуации необходимости подключения к двум базам данных с одинаковой схемой и не будет работать, если схемы немного отличаются, поскольку они не могут использовать один и тот же интерфейс.

Техника также требует, чтобы вы не забывали повторно добавлять ссылку на интерфейс каждый раз, когда вы заново генерируете класс db (в данном случае - класс TnsDb), и обновлять его каждый раз, когда вы меняете какие-либо методы в классе db.

Во всяком случае, я надеюсь, что это поможет любому с той же проблемой, что и у меня.Спасибо всем, кто помог мне решить эту проблему.

0 голосов
/ 05 июня 2018

Вы упоминаете, что каждая база данных имеет одинаковую структуру, но ваши функции используют разные контексты БДВы не можете использовать динамический объект в этом контексте, используя динамический объект.

Поскольку ваша база данных имеет ту же структуру, вы можете просто изменить строку подключения на базу данных при инициализации DbContext.Если вы действительно хотите использовать отдельные контексты БД, то вам следует использовать тот факт, который ваши функции возвращают

IMyDatabase
{
BbSet<Model1> Model1{get;set;}
BbSet<Model2> Model2{get;set;}
}
TnsDb:IMyDatabase
{
BbSet<Model1> Model1{get;set;}
BbSet<Model2> Model2{get;set;}
}
SngDb:IMyDatabase
{
BbSet<Model1> Model1{get;set;}
BbSet<Model2> Model2{get;set;}
}

, и вам обоим из контекста необходимо реализовать это, тогда ваши функции могут быть такими:

public static IMyDatabase GetDb(string scope = "dev") {
dynamic db;

if (Globals.db == null) {
    switch (scope.ToLower()) {
    case "tns":
        return new TnsDb();

    case "sng":
        return new SngDb();

    default:
        return new TnsDb();
    }
}

Но вы не должны использовать два отдельных контекста БД, достаточно одного в вашем случае с другой строкой соединения.

Хотя использование статических функций для этой цели не очень хорошо, вы можете использовать некоторый шаблон репозитория, используя зависимостьинъекции

...