简体   繁体   中英

Entity Framework won't save changes in different injected dbContext

The problem:

Changes to Orders aren't being saved to the DB when a dbcontext injected into CustomersRepository is used before adding an Order using the OrdersRepository

Setup Details

Latest C#, .net 6.0, EF 6.0, SQL Server running on local machine. I'm using a variation on Clean Architecture. I have 2 different repositories: CustomersRepository and OrdersRepository. Each one injects a dbContext. All injected dependencies use Scoped: services.AddScoped<ICustomersRepository, CustomersRepository>();

The problem Code

// this first line is the problem
var currentCustomer = await customersRepository.GetCustomer(int id); // remove this line and it saves to the DB when CreateOrder() is called. Why??

var newOrder = new Order() { CustomerId = currentCustomer.Id };
var orderId = await ordersRepository.CreateOrder(newOrder); // doesn't save to db here or throw any error.
await customersRepository.SaveCustomer(currentCustomer); // saves the newOrder to the db here, or errors if newOrder is invalid. 

CustomersRepository

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="dbContext"></param>
        public CustomersRepository(ApplicationDbContext dbContext)
        {
            this.dbContext = dbContext;
        }

        public async Task<int> SaveCustomer(Customer customer)
        {
            dbContext.Customers.Update(customer);            

            await dbContext.SaveChangesAsync();
            return customer.Id;
        }

OrdersRepository

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="dbContext"></param>
        public OrdersRepository(ApplicationDbContext dbContext)
        {
            this.dbContext = dbContext;
        }

        public async Task<int> CreateOrder(Order order)
        {
            await dbContext.Orders.AddAsync(order);
            await dbContext.SaveChangesAsync();
            return order.Id;
        }

What is expected

  • Why do I have to call customersRepository.SaveCustomer() to save an Order?
  • What is the correct way to save the Order, or what am I doing wrong?
  • If I don't retrieve the currentCustomer, it works as expected and ordersRepository.CreateOrder() adds the new order to the db (or errors).
  • If I don't call customersRepository.SaveCustomer() nothing is changed in the db and no sql errors are thrown.
  • I want to clarify that an order doesn't have to belong to a customer, it's optional.

Figured it out... The reason it wasn't saving is because I tied the Customer to the Order by setting newOrder.CustomerId = xxx.

The problem is this:

  1. EF started tracking currentCustomer once I retrieved it from the db.
  2. After creating the new Order I assigned the newOrder.CustomerId = currentCustomer.Id.
  3. When I called dbContext.SaveChangesAsync(newOrder) , EF noticed the dependency between the currentCustomer and the newOrder since currentCustomer was still in the dbContext.
  4. When this happens, EF is smart enough to know the currentCustomer needs to be updated at the same time so the newOrder is assigned to it. EF then puts the newOrder in a "Detached" state. When this happens no query is ran. Thus nothing happens - no errors, no success... yet.
  5. Finally I call dbContext.Update(currentCustomer) which automagically changes the state of the newOrder to "Added" .
  6. At this point I can call dbContext.SaveChangesAsync() and both the newOrder and the currentCustomer are updated to the DB in the same transaction (EF does the transaction automatically). I think it behaves this way to avoid orphaning a record, in my case, orphaning the new Order record.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM