【问题标题】:Entire DB get duplicated after saving records保存记录后整个数据库被复制
【发布时间】:2017-02-05 04:06:55
【问题描述】:

您好,我使用的是 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; }
}

【问题讨论】:

  • “整个数据库被复制”到底是什么意思?所有表中的所有记录?
  • 你也可以展示你的jquery方法吗?
  • 是所有表中的所有记录
  • jequery方法是什么
  • 这个方法怎么调用?

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


【解决方案1】:

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

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

让我们快速看看控制器内部发生了什么:

  • 您会得到一个由浏览器发布的新实例(在您的情况下是通过 jquery)

我假设您发布了 ALL 的模型属性(如果您不发布,这将在您让 EF 持久化您的更改后将一些属性设置为其默认值等)。请注意,此时 EF 不知道此对象,因为 EF 不跟踪它的状态。仅在将其添加到 DbSet 或例如您从数据库中加载它,我们您将其手动附加Datacontext。这是您重新插入数据的主要原因 - EF 不知道该对象,因此不知道它需要更新。

  • Order.OrderNumber = Guid.NewGuid();

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

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

你可以做些什么来解决技术问题:

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

db.Orders.Attach(Order);

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

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

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

所以从技术上讲,这应该可以解决您的问题 - 您可以阅读更多关于此的信息,例如 here,但我想提点其他内容:

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

  • 安全性

您为我的包含外键属性建模,这些属性可能会被修改但不应该被修改(想象用户选择了他不应该选择的东西)。这可以通过使用允许您包含/排除属性的 BindAttribute 来改进。 See msdn on BindAttribute

  • 灵活性

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

开始创建一个单独的 Viewmodel 可能是个好主意,它只保存页面所需的数据(从而使 BindAttribute 的使用过时)。

【讨论】:

    猜你喜欢
    • 2020-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-25
    相关资源
    最近更新 更多