【问题标题】:ASP.Net MVC Duplicate Key Exception On InsertASP.Net MVC 插入时出现重复键异常
【发布时间】:2019-08-24 07:52:14
【问题描述】:

尝试将我的订单插入数据库时​​,我遇到了一个奇怪的重复键异常。订单具有将用户与订单联系起来的用户关系。

我不确定为什么会发生重复异常,因为我正在从数据库中获取用户,然后在插入之前将其分配给订单。

我的用户上下文只是用户的 IRepository。

信息

  • 使用 EF 版本 6.2.0

导演

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

Ninject 绑定

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;
    }
}

动作

[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; }
}

订购

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; }
}

基础实体

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

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

IRepository 实现

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;
    }
}

不知道是不是我理解错了。

【问题讨论】:

  • 订单表的主键是什么?
  • @Harry 主键继承自BaseEntity。
  • @Harry 也只是提一下。它不会在订单主键上崩溃,它在插入时在分配的用户主键上崩溃。我已经调试并验证了我正在查询的用户实际上是从数据库返回一个用户。然后我分配它,插入它,然后它在分配的用户 ID 上崩溃。
  • 我多年没有使用 .NET。我相信用户是持久化的,您可以通过将 objectTrackingEnabled 设置为 false 来避免它被持久化。
  • 因为您正在从不同的上下文加载用户。就 OrderContext 而言,该用户是“新用户”。从 OrderContext 加载用户,而不是 UserContext。有界上下文不应“共享”实体。您可以通过将用户附加到 OrderContext,但是您首先需要检查 OrderContext 的本地信息,以查看它是否尚未“了解”该用户。

标签: c# asp.net entity-framework model-view-controller


【解决方案1】:

看起来问题是因为您的 User 和 Order 来自不同的上下文...我看不到您在 ninject 中注册 DbContext 的位置,但您想确保注册它in request scope。这将确保您在单个请求中为所有操作获得相同的上下文。

【讨论】:

  • 你我的朋友真棒。感谢您的建议。我在请求范围内的 ninject 中注册了我的上下文并且它起作用了!
猜你喜欢
  • 2015-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多