保存记录后,整个数据库都会重复

时间:2016-09-27 13:35:02

标签: sql sql-server entity-framework model-view-controller

您好我正在使用SQL Server 2014 我正在使用ef6 和mvc5 每次我尝试保存订单时,整个数据库都会重复,请帮忙 订单控制器如下 我看着jquery.unobtrusive-ajax,我认为它已被使用过了 并且项目中没有返回部分视图

public class OrderController : Controller
{

    // GET: Order
    [HttpGet]
    public ActionResult Index()
    {

        return View(new Order());
    }
    [HttpPost]
    [ValidateInput(true)]
    public ActionResult Index(Order Order)
    {
        try
        {
            //OrderValidator validator = new OrderValidator();

            var upload = Request.Files["ticketFile"];
            if (ModelState.IsValid)//&& validator.Validate(Order).IsValid)
            {
                using (SaliceContext db = new SaliceContext())
                {
                    //bool isDetached = db.Entry(Order).State == EntityState.Detached;
                    //if (isDetached)
                    //  db.Orders.Attach(Order);
                    //db.ProxyCreationEnabled = false;
                    //db.Entry(Order).State = EntityState.Added;
                    //db.Entry(Order).State = EntityState.Detached;
                    Order.OrderNumber = Guid.NewGuid();
                    db.Orders.Add(Order);
                    db.SaveChanges();
                    if (upload != null && upload.ContentLength > 0 && (Path.GetExtension(upload.FileName) == ".pdf" || Path.GetExtension(upload.FileName) == ".docx"))
                    {
                        string path = Path.Combine(SaliceConstants.LOI, Order.id.ToString() + Path.GetExtension(upload.FileName));//.Replace("\\", "/");
                        upload.SaveAs(Server.MapPath(path));
                        Order.File = path;
                        db.SaveChanges();
                    }
                    db.Dispose();
                }

                return RedirectToAction("SaleConfirmed", "Order", new { orderNumber = Order.OrderNumber });
                //return "Order Saved your comfirmation key: " + Order.OrderNumber;
            }

        }
        catch(Exception ex)
        {
            ViewBag.Error = "An error happend"; return RedirectToAction("Error","Error");
            //return "An error happend";
        }
        return View(new Order());//"An error happend";

    }
    public ActionResult SaleConfirmed(Guid orderNumber)
    {
        try
        {

            ViewBag.Number = orderNumber;
            return View();
        }
        catch
        {
            ViewBag.Error = "An error happend"; return RedirectToAction("Error", "Error");
        }
        return View();
    }

}

实体

public class Order
{

    public Order()
    {
        using (SaliceContext db = new SaliceContext())
        {
            this.Ports = db.Ports.ToList();
            this.PaymentTypes = db.PaymentTypes.ToList();
            this.Products = db.Products.ToList();
            this.Grades = db.Grades.ToList();
            this.Packings = db.Packings.ToList();
            this.Inspections = db.Inspections.ToList();
            this.OrderNumber = new Guid();
            db.Dispose();
        }
    }
    [Key]
    public int id { get; set; }
    public Guid OrderNumber { get; set; }
    [LocalDisplayName("Name")]
    [Required(ErrorMessage = "*")]
    [MaxLength(25, ErrorMessageResourceName = "MaxLength",
        ErrorMessageResourceType = typeof(ValidationMessages))]
    public string Name { get; set; }
    [LocalDisplayName("LastName")]
    [Required(ErrorMessage = "*")]
    //[Required(ErrorMessageResourceName = "Required",
    //  ErrorMessageResourceType = typeof(ValidationMessages))]
    [MaxLength(25, ErrorMessageResourceName = "MaxLength",
        ErrorMessageResourceType = typeof(ValidationMessages))]
    public string LastName { get; set; }
    [LocalDisplayName("Compay")]
    [Required(ErrorMessage = "*")]
    //[Required(ErrorMessageResourceName = "Required",
    //  ErrorMessageResourceType = typeof(ValidationMessages))]
    [MaxLength(25, ErrorMessageResourceName = "MaxLength",
        ErrorMessageResourceType = typeof(ValidationMessages))]
    public string Company { get; set; }
    [LocalDisplayName("Position")]
    [Required(ErrorMessage = "*")]
    //[Required(ErrorMessageResourceName = "Required",
    //  ErrorMessageResourceType = typeof(ValidationMessages))]
    [MaxLength(25, ErrorMessageResourceName = "MaxLength",
        ErrorMessageResourceType = typeof(ValidationMessages))]
    public string Position { get; set; }
    [LocalDisplayName("Country")]
    [Required(ErrorMessage = "*")]
    //[Required(ErrorMessageResourceName = "Required",
    //  ErrorMessageResourceType = typeof(ValidationMessages))]
    [MaxLength(25, ErrorMessageResourceName = "MaxLength",
        ErrorMessageResourceType = typeof(ValidationMessages))]
    public string Country { get; set; }
    [LocalDisplayName("City")]
    [Required(ErrorMessage = "*")]
    //[Required(ErrorMessageResourceName = "Required",
    //  ErrorMessageResourceType = typeof(ValidationMessages))]
    [MaxLength(25, ErrorMessageResourceName = "MaxLength",
        ErrorMessageResourceType = typeof(ValidationMessages))]
    public string City { get; set; }
    [LocalDisplayName("ContactNo")]
    [Required(ErrorMessage = "*")]
    //[Required(ErrorMessageResourceName = "Required",
    //  ErrorMessageResourceType = typeof(ValidationMessages))]
    [MaxLength(25, ErrorMessageResourceName = "MaxLength",
        ErrorMessageResourceType = typeof(ValidationMessages))]
    public string ContactNo { get; set; }
    [Display(Name = "Email address")]
    [Required(ErrorMessage = "*")]
    //[Required(ErrorMessage = "The email address is required")]
    [EmailAddress(ErrorMessage = "Invalid Email Address")]
    public string Email { get; set; }
    [LocalDisplayName("PortName")]
    //[Required(ErrorMessage = "*")]
    //[Required(ErrorMessageResourceName = "Required",
    //  ErrorMessageResourceType = typeof(ValidationMessages))]
    //[MaxLength(25, ErrorMessageResourceName = "MaxLength",
    //  ErrorMessageResourceType = typeof(ValidationMessages))]
    public string PortName { get; set; }
    [LocalDisplayName("PortValue")]
    //[Required(ErrorMessage = "*")]
    //[Required(ErrorMessageResourceName = "Required",
    //  ErrorMessageResourceType = typeof(ValidationMessages))]
    //[MaxLength(25, ErrorMessageResourceName = "MaxLength",
    //  ErrorMessageResourceType = typeof(ValidationMessages))]
    public string PortValue { get; set; }
    [LocalDisplayName("PortId")]
    [Required(ErrorMessage = "*")]
    //[Required(ErrorMessageResourceName = "Required",
    //  ErrorMessageResourceType = typeof(ValidationMessages))]
    public int PortId { get; set; }
    [LocalDisplayName("PortTypeId")]
    [Required(ErrorMessage = "*")]
    //[Required(ErrorMessageResourceName = "Required",
    //  ErrorMessageResourceType = typeof(ValidationMessages))]
    public int PortTypeId { get; set; }
    public virtual List<Port> Ports { get; set; }
    [LocalDisplayName("PaymentTypeId")]
    [Required(ErrorMessage = "*")]
    //[Required(ErrorMessageResourceName = "Required",
    //  ErrorMessageResourceType = typeof(ValidationMessages))]
    public int PaymentTypeId { get; set; }
    public virtual List<PaymentType> PaymentTypes { get; set; }
    [LocalDisplayName("Currency")]
    [Required(ErrorMessage = "*")]
    //[Required(ErrorMessageResourceName = "Required",
    //  ErrorMessageResourceType = typeof(ValidationMessages))]
    [MaxLength(25, ErrorMessageResourceName = "MaxLength",
        ErrorMessageResourceType = typeof(ValidationMessages))]
    public string Currency { get; set; }
    [LocalDisplayName("ProductId")]
    [Required(ErrorMessage = "*")]
    //[Required(ErrorMessageResourceName = "Required",
    //  ErrorMessageResourceType = typeof(ValidationMessages))]
    public int ProductId { get; set; }

    public virtual List<Product> Products { get; set; }
    [LocalDisplayName("GradeId")]
    [Required(ErrorMessage = "*")]
    //[Required(ErrorMessageResourceName = "Required",
    //  ErrorMessageResourceType = typeof(ValidationMessages))]
    public int GradeId { get; set; }
    public virtual List<Grade> Grades { get; set;}
    [LocalDisplayName("PackingId")]
    [Required(ErrorMessage = "*")]
    //[Required(ErrorMessageResourceName = "Required",
    //  ErrorMessageResourceType = typeof(ValidationMessages))]
    public int PackingId { get; set; }
    public virtual List<Packing> Packings { get; set; }
    [LocalDisplayName("Packing")]
    //[Required(ErrorMessage = "*")]
    //[Required(ErrorMessageResourceName = "Required",
    //          ErrorMessageResourceType = typeof(ValidationMessages))]
    //[MaxLength(25, ErrorMessageResourceName = "MaxLength",
    //          ErrorMessageResourceType = typeof(ValidationMessages))]
    public string Packing { get; set; }
    [LocalDisplayName("InspectionId")]
    [Required(ErrorMessage = "*")]
    //[Required(ErrorMessageResourceName = "Required",
    //          ErrorMessageResourceType = typeof(ValidationMessages))]
    public int InspectionId { get; set; }
    public virtual List<Inspection> Inspections { get; set; }
    [LocalDisplayName("LOI")]
    [Required(ErrorMessage = "*")]
    //[Required(ErrorMessageResourceName = "Required",
    //          ErrorMessageResourceType = typeof(ValidationMessages))]
    //[MaxLength(25, ErrorMessageResourceName = "MaxLength",
    //          ErrorMessageResourceType = typeof(ValidationMessages))]
    public string LOI { get; set; }
    public string File { get; set; }
}

1 个答案:

答案 0 :(得分:1)

我认为技术问题是您的代码中的以下几行:

Order.OrderNumber = Guid.NewGuid();
db.Orders.Add(Order);
db.SaveChanges();

让我们快速了解一下控制器内部发生的事情:

  • 您获得了浏览器发布的新实例(在您的情况下通过jquery)

我假设您要发布所有模型属性(如果您不这样做,这会在您使EF保持更改后将某些属性设置为其默认值等)。请注意,此时 EF不知道此对象,因为EF不会跟踪其状态。只有在将其添加到DbSet或例如DbSet后才会跟踪它。您从数据库加载它,我们附加手动加载到 Datacontext 。这是您重新插入数据的主要原因 - EF不知道对象,因此不知道它需要更新。

  • Order.OrderNumber = Guid.NewGuid();

您正在修改相同订单的OrderNumber,这似乎不正确(您将在保存后更新它正常工作)。我不知道这是否是主键 - 如果这是他们的情况,我假设你只做了这个,因为你在调用Savechanges(主键通道)时遇到了SqlException

  • 您将提交的订单添加到DbSet(db.Orders.Add)
  • 您调用SaveChanges()会保留(新)订单。

您可以采取哪些措施来解决技术问题:

正如您的代码示例所示,您已经与对象 EntityState 进行了搏斗。 正如我上面所写,EF不会跟踪提交的订单。您可以添加以下内容(因为您似乎已经尝试过):

db.Orders.Attach(Order);

这将&#34;重新添加&#34; EF的对象。我们在这里做的是手动告诉EF这个对象(带有它的ID)是从数据库加载的,而是从不同的DbContext(在显示表单/数据的请求中)加载的。 EF DbContext根本无法记住&#34;跨多个WebRequests的对象(因为DbContext在请求之间处理)。 但问题是,EF对象的状态做了什么。在附加对象时,EF将其状态设置为未更改,因为它不知道自加载以来哪些属性发生了更改。 您可以将实体的状态更改为之后修改(因此告知EF&#34;它已更改,在调用SaveChanges时更新所有属性()&#34;):

context.Entry(Order).State = EntityState.Modified;

这会将所有属性标记为已更改(没有Navigationproperties)。

从技术上讲,这应该可以解决您的问题 - 您可以阅读更多相关内容here,但我想提一下其他内容:

通常(至少在我看来)发布完整的模型模型不是一个好主意。问题是为什么?

  • 安全

您对我的包含外键属性进行建模,该外键属性可能已被修改但不应被修改(假设用户选择了他不应该选择的内容)。这可以通过使用允许您包含/排除属性的BindAttribute来改进。 See msdn on BindAttribute

  • 灵活性

您的模型上有很多属性,这可能只是UI问题所必需的。由于您只有1个模型,因此您无法以不同的形式(例如验证属性等)以不同方式显示相同的数据。例如,在Create usecase中,添加信息消息可能是可选的,但在更新时可能需要它。

最好开始创建一个单独的 Viewmodel ,它只保存页面所需的数据(从而使得例如BindAttribute的使用过时)。