SaveChanges () и добавление в БД не работает - PullRequest
1 голос
/ 08 апреля 2019

Я работаю над добавлением Entity Framework в наше веб-приложение asp.net MVC 5, но у меня возникают трудности с сохранением изменений и добавлением в базу данных. Я настроил UnitOfWork с помощью базового репозитория BaseRepository, и я попробовал несколько вещей, пытаясь заставить это работать. во-первых, я подумал, что с помощью AutoFac можно внедрить мой репо в UnitOfWork, как показано ниже:

public UnitOfWork(IServiceItem serviceItem
        , ITechServiceItem techServiceItem
        , ITechnicianTime technicianTime
        , ISproc sproc
        , IRepairOrder repairOrder
        , ICustomer customer
         , IRepairOrderStatus repairOrderStatus
        , IRepairOrderUnit repairOrderUnit
        , IFiles files
        , IPartInventory partInventory
        , IRepairOrderItems repairOrderItems
        )
        {
            RepairOrderItems = repairOrderItems;
            PartInventory = partInventory;
            Files = files;
            RepairOrderUnit = repairOrderUnit;
            RepairOrderStatus = repairOrderStatus;
            RepairOrder = repairOrder;
            Customer = customer;
            Sproc = sproc;
            ServiceItem = serviceItem;
            TechServiceItem = techServiceItem;
            TechnicianTime = technicianTime;
        }

и мой BaseRepo похож на

public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        protected DataDbContext _db;

       public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        protected DataDbContext _db;

        internal void GetData()
        {
            if (_db == null)
            {
                string accountNumber = HttpContext.Current.User.Identity.GetCompanyAccountNumber();
                var connectionToken = ConfigurationManager.AppSettings["LoginSplitToken"];
                _db = new DataDbContext(ConfigurationManager.ConnectionStrings["NameOfConnString"].ConnectionString.Replace(connectionToken, accountNumber));
            }
        }

        public TEntity Get(int id)
        {
            return _db.Set<TEntity>().Find(id);
        }

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

        public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
        {
            return _db.Set<TEntity>().Where(predicate);
        }

        public void Add(TEntity entity)
        {
            _db.Set<TEntity>().Add(entity);
        }

        public void AddRange(IEnumerable<TEntity> entities)
        {
            _db.Set<TEntity>().AddRange(entities);
        }

        public void Remove(TEntity entity)
        {
            _db.Set<TEntity>().Remove(entity);
        }

        public void RemoveRange(IEnumerable<TEntity> entities)
        {
            _db.Set<TEntity>().RemoveRange(entities);
        }

        public int CompleteData()
        {
            return _db.SaveChanges();
        }

        public TEntity Get(int id)
        {
            return _db.Set<TEntity>().Find(id);
        }

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

        public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
        {
            return _db.Set<TEntity>().Where(predicate);
        }

        public void Add(TEntity entity)
        {
            _db.Set<TEntity>().Add(entity);
        }

        public void AddRange(IEnumerable<TEntity> entities)
        {
            _db.Set<TEntity>().AddRange(entities);
        }

        public void Remove(TEntity entity)
        {
            _db.Set<TEntity>().Remove(entity);
        }

        public void RemoveRange(IEnumerable<TEntity> entities)
        {
            _db.Set<TEntity>().RemoveRange(entities);
        }

        public int CompleteData()
        {
            return _db.SaveChanges();
        }
}

и моя заставка. Конфигурация

 public void Configuration(IAppBuilder app)
        {
            var builder = new ContainerBuilder();
            HttpConfiguration config = GlobalConfiguration.Configuration;

            // REGISTER DEPENDENCIES
            builder.RegisterType<EverLogicDbContext>().AsSelf().InstancePerRequest();
            builder.RegisterType<ApplicationUserManager>().AsSelf().InstancePerRequest();
            builder.RegisterType<ApplicationSignInManager>().AsSelf().InstancePerRequest();
            builder.Register(c => HttpContext.Current.GetOwinContext().Authentication).InstancePerRequest();
            builder.Register(c => HttpContext.Current.User).InstancePerRequest();
            builder.Register(c => app.GetDataProtectionProvider()).InstancePerRequest();

            builder.RegisterType<ApplicationUserStore>().As<IUserStore<EverLogicMamber, int>>()
                  .WithParameter(new TypedParameter(typeof(ISecurityOfWork), new SecurityOfWork(new SecurityDbContext())))
                .InstancePerRequest();

            //Database
            builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerRequest();
            builder.RegisterType<SecurityOfWork>().As<ISecurityOfWork>().InstancePerRequest();
            //Service
            builder.RegisterType<TechnicianTimeService>().As<ITechnicianTimeService>().InstancePerRequest();
            builder.RegisterType<PartService>().As<IPartService>().InstancePerRequest();
            builder.RegisterType<TechServiceItemService>().As<ITechServiceItemService>().InstancePerRequest();
            //Repo
            builder.RegisterType<Company>().As<ICompany>().InstancePerRequest();
            builder.RegisterType<Views>().As<IViews>().InstancePerRequest();

            builder.RegisterType<RepairOrderItems>().As<IRepairOrderItems>().InstancePerRequest();
            builder.RegisterType<PartInventory>().As<IPartInventory>().InstancePerRequest();
            builder.RegisterType<Files>().As<IFiles>().InstancePerRequest();
            builder.RegisterType<TechDashboardService>().As<ITechDashboardService>().InstancePerRequest();
            builder.RegisterType<RepairOrderUnit>().As<IRepairOrderUnit>().InstancePerRequest();
            builder.RegisterType<RepairOrderStatus>().As<IRepairOrderStatus>().InstancePerRequest();
            builder.RegisterType<Customer>().As<ICustomer>().InstancePerRequest();
            builder.RegisterType<ServiceItem>().As<IServiceItem>().InstancePerRequest();
            builder.RegisterType<RepairOrder>().As<IRepairOrder>().InstancePerRequest();
            builder.RegisterType<Sproc>().As<ISproc>().InstancePerRequest();
            builder.RegisterType<TechServiceItem>().As<ITechServiceItem>().InstancePerRequest();
            builder.RegisterType<TechnicianTime>().As<ITechnicianTime>().InstancePerRequest();

            // REGISTER CONTROLLERS SO DEPENDENCIES ARE CONSTRUCTOR INJECTED
            builder.RegisterControllers(typeof(MvcApplication).Assembly);
            builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
            builder.RegisterWebApiFilterProvider(config);
            builder.RegisterWebApiModelBinderProvider();

            var container = builder.Build();

            // REPLACE THE MVC DEPENDENCY RESOLVER WITH AUTOFAC
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

            app.UseAutofacMiddleware(container);
            app.UseAutofacMvc();
            config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

            ConfigureAuth(app);
        }

Но при такой настройке база данных не обновляет и не добавляет новые объекты. Затем я попытался удалить Depency инъекцию из UnitOfWork и настроить UnitOfWork как

 protected DataDbContext _db;
      public UnitOfWork(DataDbContext context)
        {
            GetData();
            RepairOrderItems = new RepairOrderItems(_db);
            PartInventory = new PartInventory(_db);
            Files = new Files(_db);
            RepairOrderUnit = new RepairOrderUnit(_db);
            RepairOrderStatus = new RepairOrderStatus(_db);
            RepairOrder = new RepairOrder(_db);
            Customer = new Customer(_db);
            Sproc = new Sproc(_db);
            ServiceItem = new ServiceItem(_db);
            TechServiceItem = new TechServiceItem(_db);
            TechnicianTime = new TechnicianTime(_db);
        }
  internal void GetData()
        {
            if (_db == null)
            {
                string accountNumber = HttpContext.Current.User.Identity.GetCompanyAccountNumber();
                var connectionToken = ConfigurationManager.AppSettings["LoginSplitToken"];
                _db = new DataDbContext(ConfigurationManager.ConnectionStrings["NameOfConnString"].ConnectionString.Replace(connectionToken, accountNumber));
            }
        }

и перемещение SaveChanges из BaseRepo в UnitOfWork, но все равно ничего не сохраняется или не добавляется в базу данных. Чего мне не хватает ????

1 Ответ

1 голос
/ 08 апреля 2019

TL; DR проблема в том, что все ваши репозитории используют отдельные, независимые DbContexts, поэтому DbContext, введенный в ваш UnitOfWork, не имеет ожидающих изменений при вызове SaveChanges наименно поэтому вы не видите никаких изменений в базе данных.

Для правильной работы Unit Work, ваш класс UnitOfWork и все классы репозитория, которые должен выполнять ваш кодпостоянство данных, все должны иметь один и тот же экземпляр DbContext.В вашем коде ясно, что каждый репозиторий имеет метод фабрики для создания своего собственного, независимого DbContext экземпляра.

  • Удалите фабричный метод GetData() из своего класса BaseRepository, и вместо этого,требует, чтобы экземпляр вашего экземпляра EverLogicDbContext был внедрен в конструктор BaseRepository AutoFac.Это потребует, чтобы все ваши подклассы репозитория также имели конструктор, принимающий те же EverLogicDbContext.
  • Согласно вашему последнему редактированию, класс UnitOfWork должен принимать тот же общий EverLogicDbContext, что и репозитории.использовать.Поскольку вы пометили asp.net-mvc, тогда RequestPerInstance область действия времени подходит для вашего сценария.
  • Ваш класс UnitOfWork должен контролировать метод SaveChanges(Async), поэтому удалите метод CompleteData изBaseRepository класс.
  • Как вы, похоже, уже сделали, DbContext необходимо зарегистрировать InstancePerRequest:

builder.RegisterType<EverLogicDbContext>().AsSelf().InstancePerRequest();

Есливсе это правильно связано:

  • AutoFac создаст экземпляр вашего конкретного DbContext в первый раз, когда это потребуется во время обработки каждого запроса.
  • Затем все хранилища будут совместно использоватьтот же экземпляр DbContext для срока действия запроса, и DbContext будет отслеживать промежуточные изменения, сделанные вашими службами.
  • UnitOfWork, внедренный в вашу основную "бизнес-логику" (например, Controller или Orchestrator /Затем обработчик) сможет Commit выполнить действия, просто вызвав SaveChangesAsync на общем DbContext.Все это будет происходить при одном подключении к базе данных, поэтому это будет легкая транзакция.

Как и в других комментариях выше, IMO Entity Framework - это уже платформа высокого уровня со встроенной поддержкой транзакций, поэтомумало смысла в чрезмерной разработке шаблона «UnitOfWork», если все действия ACID будут выполняться в одной и той же базе данных (и могут быть заключены в один и тот же DbContext).

...