Entire DB get duplicated after saving records

Question!

hi i am using SQL server 2014 and i am using ef6 and mvc5 every time i try to save an order entire db gets duplicated please help order controller is as follow i looked at jquery.unobtrusive-ajax i think it is been used one and there are no return partialview in project

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

}

entity

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


Answers

The technical problem in my opinion are the following lines in your code:

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

Let's take a quick look at what is happening inside you controller:

  • You get a new instance posted by the browser (via jquery in your case)

I assume you are posting ALL of the models properties (if you don't, this will set some properties to their default value etc after you make EF persist your changes). Note that at this time EF does not know this object, since it's state is not tracked by EF. It is only tracked after you add it to a DbSet or e.g. you load it from the database, our you attach it manually to the Datacontext. This is the main reason why you are reinserting the data - EF does not know the object and therefore does not know that it needs to be updated.

  • Order.OrderNumber = Guid.NewGuid();

You are modifying the OrderNumber of the same order, which seems not correct (you would update it after saving would work correctly). I do not know if this is the primary key - if this i they case, I assume you only did this, because you got an SqlException when calling Savechanges (Primary Key Vialation)

  • You add the submitted order to the DbSet (db.Orders.Add)
  • You call SaveChanges() which persists the (new) order.

What you could do to solve the technical problem:

As your code example shows, you already wrestled with the object's EntityState. As I already wrote above, the submitted Order is not tracked by EF. You could add the following (as it seems you already tried):

db.Orders.Attach(Order);

This will "re-add" the object to EF. What we are doing here is to manually tell EF that this object (with it's ID) was loaded from the database, but from a different DbContext (in the request that displayed the form/data). EF DbContext simply cannot "remember" the object accross multiple WebRequests (since the DbContext gets disposed between the requests). But the question is, what EF does with the object's State. When Attaching an object, EF sets it's state to Unchanged, since it does not know which properties changed since it it was loaded. You could change the entity's state to modified after (thus telling EF "it changed, update all properties when calling SaveChanges()"):

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

This will mark all properties as changed (without Navigationproperties).

So technically this should solve your problem - you can read more about this for exampe here, but I'd like to mention something else:

Usually (at least in my opinion) it's not a good idea to post the complete model model. The question is why?

  • Security

You model my contain Foreign Key Properties which might be modified but should not be modified (imagine the user selecting something that he should not be able to select). This could be improved by using the BindAttribute which allows you to include/exclude properties. See msdn on BindAttribute

  • Flexibility

You have a lot of attributes on your model, which may only be required for UI concerns. Since you only have 1 model, you cannot display the same data differently in a different form (e.g. validation attributes etc...). For example in a Create usecase it may be optional to add an inforamtional message, but when updateing it it may be required.

It may be a good idea to start creating a separate Viewmodel, which only holds the data required for the page (and thus makes the usage of e.g. the BindAttribute obsolete).



I am trying to guess what you are trying to do since I have no idea what your "row" looks like. I assume you have the variable columns which is a list of column names. If that is the case, please consider this code snippet:

class SalesOrder(object):
    def __init__(self, columns, row):
        """ Transfer all the columns from row to this object """
        for name in columns:
            value = getattr(row, name)
            setattr(self, name, value)
        self.long, self.lat = getLongLat(self.post_code)

    def cancel(self):
        self.status = 'cancelled'

    def as_row(self):
        return [getattr(self, name) for name in columns]

    def __repr__(self):
        return repr(self.as_row())

# Create the dictionary of class
orders = {row.order_id: SalesOrder(columns, row) for row in cursor}

# Cancel
cancelled_orders = getCancelledOrders()
for order_id in cancelled_orders:
    orders[order_id].cancel()

# Print all sales orders
for sales_order in orders.itervalues():
    print(sales_order)

At the lowest level, we need to be able to create a new SalesOrder object from the row object by copying all the attributes listed in columns over. When initializing a SalesOrder object, we also calculate the longitude and latitude as well.

With that, the task of creating the dictionary of class objects become easier:

orders = {row.order_id: SalesOrder(columns, row) for row in cursor}

Our orders is a dictionary with order_id as keys and SalesOrder as values. Finally, the task up cancelling the orders is the same as your code.

In addition to what you have, I created a method called as_row() which is handy if later you wish to write a SalesOrder object into a CSV or database. For now, I use it to display the "raw" row. Normally, the print statement/function will invoke the __str__() method to get a string presentation for an object, if not found, it will attempt to invoke the __repr__() method, which is what we have here.

By : Hai Vu


you would require to specific

@property (nonatomic) BOOL isInAirmode;

as

@property (assign,getter= _isInAirmode) BOOL isInAirmode;
By : aman.sood


This video can help you solving your question :)
By: admin