0

I'm new to EF (table first) and I don't know why these related entities are not saving at all to my database. These are the related entities, UserProfile has a set of Carts

public partial class UserProfile
    {
        public UserProfile()
        {
            Cart = new HashSet<Cart>();
            Naquestions = new HashSet<Naquestions>();
        }

        public int Id { get; set; }
        public string BotUserId { get; set; }
        public int? PrestashopId { get; set; }
        public bool Validated { get; set; }
        public int Permission { get; set; }
        public DateTime CreationDate { get; set; }

        public ICollection<Cart> Cart { get; set; }
        public ICollection<Naquestions> Naquestions { get; set; }
    }

Cart has a set of OrderLines

   public partial class Cart
    {
        public Cart()
        {
            OrderLine = new HashSet<OrderLine>();
            OrderRequest = new HashSet<OrderRequest>();
        }

        public int Id { get; set; }
        public int UserId { get; set; }
        public bool Active { get; set; }

        public UserProfile User { get; set; }
        public ICollection<OrderLine> OrderLine { get; set; }
        public ICollection<OrderRequest> OrderRequest { get; set; }
    }

And when I try to add them:

public async Task AddOrderLineToUser(string botId, OrderLine orderLine)
        {
            using (var context = ServiceProvider.CreateScope())
            {
                var db = context.ServiceProvider.GetRequiredService<GretaDBContext>();

                var user = await UserController.GetUserByBotIdAsync(botId);

                var latestCart = user.Cart.OrderByDescending(c => c.Id).FirstOrDefault();

                if (latestCart != null && latestCart.Active)
                {
                    latestCart.OrderLine.Add(orderLine);
                }
                else
                {
                    var newCart = new Cart()
                    {
                        Active = true,
                    };
                    newCart.OrderLine.Add(orderLine);
                    user.Cart.Add(newCart);
                }

                await db.SaveChangesAsync();
            }
        }

Nothing is saving to the database once db.SaveChangesAsync() is called.

  • 1
    Where does the `user` UserController get its db context from in order to run the `GetUserByBotIdAsync` method? I don't think it's the same `db` that you're calling `SaveChangesAsync` on - you're hence adding the entities to one context and calling save changes on another – Caius Jard May 13 '20 at 09:17
  • I assume when I add the `newCart` to the `user` cart set, it should be added to the database right? Since the user object was updated. – Ferran Capallera Guirado May 13 '20 at 09:18
  • Ah yes, the user comes from another context. That was one of the things that I was suspicious about. If I want to obtain an user do I have to write the code to obtain it on every context then? Can't I define a function like this but tell the new context to keep track of that object? – Ferran Capallera Guirado May 13 '20 at 09:21
  • 1
    It's also a bit odd that your class that does this work is UserController - controllers normally are solely concerned with receiving eg JSON or form data from a browser, and returning JSON/HTML or referencing a view that will build the response for the browser/remote device.. I would expect something more like a Service or Repository flavoured object to be doing the DB reading and writing, and this method of adding new carts and orderlines would be part of a repo, not outside of it. The controller would hence call upon the repo/service to create the carrt/order etc – Caius Jard May 13 '20 at 11:15

1 Answers1

0

As @Caius Jard said in the comments it seems that user comes from another context. Try

 if (latestCart != null && latestCart.Active)
 {
      orderLine.CartId = latestCart.Id;
      db.OrderLines // I assume it is name of your orderlines DbSet
         .Add(orderLine);
 }
 else
 {
      var newCart = new Cart()
      {
           Active = true,
           UserId = user.Id,
      };
      newCart.OrderLine.Add(orderLine);
      db.Carts // also assuming name of DbSet
         .Add(newCart);
 }

Also you can take a look at Attach method.

But I would say that in general you are doing something not good. Usually creating new scope is not needed, and db context should be injected in corresponding class via ctor. If you still need to create new scope it would make sense to resolve UserController also. Also is UserController an ASP controller?

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • Yeah, the idea was injecting it. But in the framework I'm working the classes that need to call these functions are Singletons. And I can't inject scoped classes like the DbContext in a Singleton. Thanks for the answer! – Ferran Capallera Guirado May 14 '20 at 07:54
  • @FerranCapalleraGuirado which DI framework are you using? If you are using Microsoft's then you can register DB context as transient(if it suits the rest of the app) Also please see this [answer](https://stackoverflow.com/a/61602061/2501279). – Guru Stron May 14 '20 at 08:36