Как использовать универсальный репозиторий, шаблон единицы работы с несколькими EDMX для нескольких баз данных

Я занимаюсь разработкой проекта, в котором есть 3 базы данных MS SQL Server.

Я использую,

  • EntityFramework 6.4.0,
  • Общий репозиторий,
  • Шаблон единицы работы репозитория.
  • ASP.Net MVC
  • Модели данных с несколькими сущностями

Мне нужно сохранить изменения в нескольких таблицах в нескольких БД как одну транзакцию (используя одну SaveChanges() метод)

Я выполнял проекты с использованием вышеуказанных шаблонов с использованием одной базы данных, одного класса UoW, одного общего репозитория. Теперь я застрял с несколькими БД.

Мой общий класс репозитория следующим образом

    public class GenericRepository<TEntity, TContext> : IGenericRepository<TEntity, TContext> 
        where TEntity : class 
        where TContext : DbContext
    {
        internal DbContext context;
        internal DbSet<TEntity> dbSet;

        public GenericRepository(DbContext context)
        {
            this.context = context;
            this.dbSet = context.Set<TEntity>();
        }


        public IEnumerable<TEntity> GetAll()
        {
            return context.Set<TEntity>().ToList();
        }


        public virtual IEnumerable<TEntity> Get(
            Expression<Func<TEntity, bool>> filter = null,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
            string includeProperties = "")
        {
            IQueryable<TEntity> query = dbSet;

            if (filter != null)
            {
                query = query.Where(filter);
            }

            foreach (var includeProperty in includeProperties.Split (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }

            if (orderBy != null)
            {
                return orderBy(query).ToList();
            }
            else
            {
                return query.ToList();
            }
        }

        public virtual TEntity GetByID(object id)
        {
            return dbSet.Find(id);
        }

        public virtual void Insert(TEntity entity)
        {
            dbSet.Add(entity);
        }

        public virtual void InsertRange(IList<TEntity> entityList)
        {
            dbSet.AddRange(entityList);
        }

        public virtual void Delete(object id)
        {
            TEntity entityToDelete = dbSet.Find(id);
            Delete(entityToDelete);
        }

        public virtual void DeleteRange(IEnumerable<TEntity> lstEntity)
        {
             dbSet.RemoveRange(lstEntity);
        }

        public virtual void Delete(TEntity entityToDelete)
        {
            if (context.Entry(entityToDelete).State == EntityState.Detached)
            {
                dbSet.Attach(entityToDelete);
            }
            dbSet.Remove(entityToDelete);
        }

        public virtual void Update(TEntity entityToUpdate)
        {
            dbSet.Attach(entityToUpdate);
            context.Entry(entityToUpdate).State = EntityState.Modified;
        }
    }

Мой класс Unit Of Work следующим образом;

    public class UnitOfWork<TContext> : IDisposable where TContext : DbContext, new()
    {
        private DbContext context;

        private IGenericRepository<TBL_RC_DATA_PHL_EmployeeData_SIN, DbContext> tbl_Data_EmployeeData_sin;
        public IGenericRepository<TBL_RC_DATA_PHL_EmployeeData_SIN, DbContext> Tbl_Data_EmployeeData_sin
        {
            get
            {
                if (this.tbl_Data_EmployeeData_sin == null)
                {
                    this.tbl_Data_EmployeeData_sin = new GenericRepository<TBL_RC_DATA_PHL_EmployeeData_SIN, DbContext>(context);
                }
                return tbl_Data_EmployeeData_sin;
            }
        }

        private IGenericRepository<TBL_RC_DATA_PHL_EmployeeData_PHL, DbContext> tbl_Data_EmployeeData_phl;
        public IGenericRepository<TBL_RC_DATA_PHL_EmployeeData_PHL, DbContext> Tbl_Data_EmployeeData_phl
        {
            get
            {
                if (this.tbl_Data_EmployeeData_phl == null)
                {
                    this.tbl_Data_EmployeeData_phl = new GenericRepository<TBL_RC_DATA_PHL_EmployeeData_PHL, DbContext>(context);
                }
                return tbl_Data_EmployeeData_phl;
            }
        }

        private IGenericRepository<TBL_RC_DATA_PHL_EmployeeData_ENG, DbContext> tbl_Data_EmployeeData_eng;
        public IGenericRepository<TBL_RC_DATA_PHL_EmployeeData_ENG, DbContext> Tbl_Data_EmployeeData_eng
        {
            get
            {
                if (this.tbl_Data_EmployeeData_eng == null)
                {
                    this.tbl_Data_EmployeeData_eng = new GenericRepository<TBL_RC_DATA_PHL_EmployeeData_ENG, DbContext>(context);
                }
                return tbl_Data_EmployeeData_eng;
            }
        }

        public UnitOfWork()
        {
            context = new TContext();
        }

        public void Save()
        {
            context.SaveChanges();
        }

        private bool disposed = false;
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    context.Dispose();
                }
            }
            this.disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }

Мои классы уровня обслуживания следующие

  public class svcEmployeeData
    {
        private UnitOfWork<DAL.RCPlusEntities> unitOfWork;

        public svcEmployeeData()
        {
            unitOfWork = new UnitOfWork<DAL.RCPlusEntities>();
        }

        public void updateEmployees(TBL_RC_DATA_PHL_EmployeeData_SIN sin, TBL_RC_DATA_PHL_EmployeeData_ENG eng)
        {
        //updating Business Logic goes here

        unitOfWork.Tbl_Data_EmployeeData_sin.Update(sin);        
        unitOfWork.Tbl_Data_EmployeeData_eng.Update(eng);
        unitOfWork.Save();

        }
}

Как преобразовать эту архитектуру в 3 EDMX по 3 базам данных...?

Заранее спасибо.

1 ответ

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

Причина, по которой вы не можете повторно использовать один и тот же класс для другой базы данных, заключается в том, что вы создаете экземпляр DbContext в UnitOfWork конструктор, как показано ниже:

private DbContext context;
public UnitOfWork()
{
    context = new TContext();
}

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

private DbContext context;
public UnitOfWork(DbContext context)
{
    this.context = context;
}

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

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

Теперь, как вы сказали:

Мне нужно сохранить изменения в нескольких таблицах в нескольких БД как одну транзакцию (с помощью одного метода SaveChanges())

и прокомментировал:

Мне нужно обрабатывать транзакции. Если при обновлении 2-й таблицы БД возникла какая-либо ошибка, необходимо откатить изменения в 1-й таблице БД. Легко сделать это с помощью одного UnitOwWork.Save()

Обратите внимание на вопрос, поднятый @Holger в комментарии.

Примечание. Транзакции между базами данных на SQL-сервере поддерживаются только на одном сервере. - Хольгер

В SaveChangesметод здесь не поможет. Вместо этого вы можете использовать TransactionScope на уровне сервиса для фиксации / отката всего пакета по базам данных.

Итак, на уровне обслуживания это выглядит примерно так:

using (TransactionScope scope = new TransactionScope())
{
    //Create unitOfWorkDb1 here
    unitOfWorkDb1.DoSomething();
    unitOfWorkDb1.Save();

    //Create unitOfWorkDb2 here
    unitOfWorkDb2.DoSomething();
    unitOfWorkDb2.Save();

    scope.Complete();
}

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

Другие вопросы по тегам