0

I am getting a strange duplicate key exception when trying to insert my order to the database. The order has a User relationship that ties a user to the order.

I am not sure why the duplicate exception is happening as I am grabbing a user from the DB and then assigning it to the order before inserting.

My user context is just an IRepository of User.

Info

  • Using EF Version 6.2.0

Ctor

public OrderManagerController(IRepository<Order> orderContext,
        IRepository<User> userContext)
{
    _orderContext = orderContext;
     userContext = userContext;
}

Ninject Binding

private static IKernel CreateKernel()
{
    var kernel = new StandardKernel();
    try
    {
        kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

        //Bind concrete classes to contracts
        kernel.Bind<IRepository<Order>>().To<SQLRepository<Order>>();
        kernel.Bind<IRepository<User>>().To<SQLRepository<User>>();
        RegisterServices(kernel);
        return kernel;
    }
    catch
    {
        kernel.Dispose();
        throw;
    }
}

Action

[HttpPost]
    public ActionResult Create(OrderManagerViewModel order)
    {
        if (!ModelState.IsValid)
            return View("Create", order);
        else
        {

            User user = _userContext.Find(order.AssignedUserId); // Grab user from DB
            //Create the order from the passed in view model and DB user
            Order orderToInsert = new Order
            {
                AssignedUser = user,
                Category = order.Category,
                Comments = order.Comments,
                CustomerName = order.CustomerName,
                EstimatedHours = order.EstimatedHours,
                SalesOrderNumber = order.SalesOrderNumber,
                LineType = order.LineType,
                OrderTotal = order.OrderTotal,
                ScheduledCompletionDate = order.ScheduledCompletionDate,
                OutDate = order.OutDate
            };
            _orderContext.Insert(orderToInsert); // Insert
            _orderContext.Commit();//Save -----Crashes with Duplicate Exception on AssignedUser.Id
            return RedirectToAction("Index");
        }
    }

OrderManagerViewModel

public class OrderManagerViewModel
{
    [RegularExpression(@"^([0-9]{8})$", ErrorMessage = "Sales order number must be 8 digits.")]
    [DisplayName("Sales Order Number")]
    [Range(10000000, 99999999)]
    public int SalesOrderNumber { get; set; }
    [DisplayName("Engineer Line Type")]
    [Range(1, 3)]
    public int LineType { get; set; }
    [Range(0, 240)]
    [DisplayName("Estimated Hours")]
    public int EstimatedHours { get; set; }
    [StringLength(50)]
    [DisplayName("Customer Name")]
    public string CustomerName { get; set; }
    [Range(0, 2000000)]
    [DisplayName("Order Total")]
    public decimal OrderTotal { get; set; }
    [StringLength(2)]
    [DisplayName("PA/SB")]
    public string Category { get; set; }
    public string FirstName { get; set; }
    public string AssignedUserId { get; set; }
    [DisplayName("Scheduled Date Out")]
    public DateTime? ScheduledCompletionDate { get; set; }
    [Display(Name = "Out Date")]
    public DateTime OutDate { get; set; }
    [StringLength(500)]
    public string Comments { get; set; }
}

Order

public class Order : BaseEntity
{
    [RegularExpression(@"^([0-9]{8})$", ErrorMessage = "Sales order number must be 8 digits.")]
    [DisplayName("Sales Order Number")]
    [Range(10000000,99999999)]
    public int SalesOrderNumber { get; set; }
    [DisplayName("Engineer Line Type")]
    [Range(1,3)]
    public int LineType { get; set; }
    [Range(0,120)]
    [DisplayName("Engineering Hours")]
    public int EngineeringHours { get; set; }
    [Range(0, 120)]
    [DisplayName("Drafting Hours")]
    public int DraftingHours { get; set; }
    [Range(0, 240)]
    [DisplayName("Estimated Hours")]
    public int EstimatedHours { get; set; }
    [StringLength(50)]
    [DisplayName("Customer Name")]
    public string CustomerName { get; set; }
    [Range(0,2000000)]
    [DisplayName("Order Total")]
    public decimal OrderTotal { get; set; }
    [StringLength(2)]
    [DisplayName("PA/SB")]
    public string Category { get; set; }
    [DisplayName("Check Out Time")]
    public DateTime? CheckedOutDate { get; set; }
    [Required]
    public User AssignedUser { get; set; }
    [DisplayName("Scheduled Date Out")]
    public DateTime? ScheduledCompletionDate { get; set; }
    [Display(Name = "Out Date")]
    public DateTime OutDate { get; set; }
    [DisplayName("Actual Date Out")]
    public DateTime? ActualCompletionDate { get; set; }
    [StringLength(500)]
    public string Comments { get; set; }
}

Base Entity

public abstract class BaseEntity
{
    public string Id { get; set; }
    public DateTimeOffset CreatedAt { get; set; }

    public BaseEntity()
    {
        Id = Guid.NewGuid().ToString();
        CreatedAt = DateTime.Now;
    }
}

IRepository implementation

public class SQLRepository<T> : IRepository<T> where T : BaseEntity
{
    internal DataContext context;
    internal DbSet<T> dbSet;

    public SQLRepository(DataContext context)
    {
        this.context = context;
        dbSet = context.Set<T>();
    }
    public IQueryable<T> Collection()
    {
        return dbSet;
    }

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

    public void Delete(string Id)
    {
        var t = Find(Id);
        if (context.Entry(t).State == EntityState.Detached)
            dbSet.Attach(t);

        dbSet.Remove(t);
    }

    public T Find(string Id)
    {
        return dbSet.Find(Id);
    }

    public void Insert(T t)
    {
        dbSet.Add(t);
    }

    public void Update(T t)
    {
        dbSet.Attach(t);
        context.Entry(t).State = EntityState.Modified;
    }
}

Not sure if maybe I am misunderstanding something.

5
  • What is the Primary Key on the order table? Commented Apr 2, 2019 at 21:55
  • @Harry The primary key is inherited from BaseEntity. Commented Apr 2, 2019 at 21:57
  • @Harry Also just to mention. It does not crash on the orders primary key, it crashes on the Assigned Users primary key when inserting. I have debugged and verified that the user I am querying is in fact returning a user from the DB. I then assign it, insert, then it crashes on the assigned user ID. Commented Apr 2, 2019 at 21:59
  • I did not work with .NET for years. I believe the user is persisted and you can avoid it to be persisted by setting objectTrackingEnabled to false. Commented Apr 2, 2019 at 22:04
  • 2
    Because you are loading the user from a different context. As far as the OrderContext is concerned, that user is "new". Load the user from the OrderContext, not UserContext. Bounded contexts should not "share" entities. You can, by attaching the user to the OrderContext, however you first need to check the OrderContext's local to see if it doesn't already "know" about that user. Commented Apr 2, 2019 at 22:05

1 Answer 1

1

It looks like the issue is because your User and Order are coming from separate contexts...I don't see where you're registering your DbContext in ninject but you want to make sure to register it in request scope. That will ensure that you get the same context for all operations within a single request.

Sign up to request clarification or add additional context in comments.

1 Comment

You my friend are awesome. Thank you for the suggestion. I registered my context in ninject with in request scope and it worked!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.