Selthien
Selthien

Reputation: 1258

ASP.Net MVC Duplicate Key Exception On Insert

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

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.

Upvotes: 0

Views: 609

Answers (1)

Michael Brown
Michael Brown

Reputation: 9153

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.

Upvotes: 1

Related Questions