Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange entity updating in Entity Framework Code-First

I'm solving the problem with updating entity before saving to database and got strange behavior.

I'm using Entity Framework 4.1 Code-First in ASP.NET MVC 3 web application. Here is model:

public class Order
{
    public int OrderId { get; set; }
    public int CarId { get; set; }
    public DateTime BeginRentDate { get; set; }
    public DateTime EndRentDate { get; set; }
    public decimal RentPrice { get; set; }
    public virtual Car Car { get; set; }
}

public class Car
{
    public int CarId { get; set; }
    public string Brand { get; set; }
    public string Model { get; set; }
    public string NumberPlate { get; set; }
    public decimal RentPrice { get; set; }
}

Each Car has a RentPrice. This price should be copied to Order's RentPrice when creating one. The car is selecting by user so initially Order.RentPrice is 0.

Here I want to copy price value:

[HttpPost]
public ActionResult Create(Order order)
{
    order.RentPrice = _context.Cars.Find(order.CarId).RentPrice;

    if (ModelState.IsValid)
    {
        _context.Orders.Add(order);
        _context.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(order);
}

It's not working because of an error on the SaveChanges that entity has validation errors. OK. I found that need first to call UpdateModel(order); and then change values.

So what I have. Working code:

_context.Orders.Add(order);
UpdateModel(order);
order.RentPrice = 777;
_context.SaveChanges();

Not working code:

_context.Orders.Add(order);
UpdateModel(order);
order.RentPrice = _context.Cars.Find(order.CarId).RentPrice;
_context.SaveChanges();

Working code (!):

_context.Orders.Add(order);
UpdateModel(order);
var t = (double)_context.Cars.Find(order.CarId).RentPrice;
order.RentPrice = (decimal)t;
_context.SaveChanges();

Can someone explain, please, what is going on here? Especially magic on the 3nd and 4th lines in the last block of code.

Update

I'm getting DbEntityValidationException: "Validation failed for one or more entities. See 'EntityValidationErrors' property for more details." From the inner exception: "OriginalValues cannot be used for entities in the Added state."

like image 367
kyrylomyr Avatar asked Aug 18 '11 16:08

kyrylomyr


2 Answers

When you get

"Validation failed for one or more entities. See 'EntityValidationErrors' property for more details." From the inner exception: "OriginalValues cannot be used for entities in the Added state."

It means there was errors such as NOT NULL collumns that were blank or other constraints , check the entity validation errors by debugging or like

try{
...
catch ( DbEntityValidationException ex )
   {
foreach ( var validationErrors in ex.EntityValidationErrors )
    {
     foreach ( var validationError in validationErrors.ValidationErrors )
     {
      System.Diagnostics.Trace.TraceInformation( "Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage );
     }
    }
}
like image 171
John Avatar answered Nov 19 '22 07:11

John


OriginalValues cannot be used for entities in the Added state.

Can be corrected by ensuring that non identity primary key fields are specified as not generated in the model.

modelBuilder
    .Entity<T>()
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
    // this can also be achieved using attributes on the entity.

The error is actually self explanatory when you have context, but baffling otherwise. The database generates two statements for the insert, the second of which is:

SELECT [PrimaryKeyId]
FROM [dbo].[Entity]
WHERE @@ROWCOUNT > 0 AND [PrimaryKeyId] = scope_identity()
/* SP:StmtCompleted... */

This statement will not return any rows for non identity columns. Hence the OriginalValues will remain unaltered in the added state. This also explains why this exception is wrapped in an OptimisticConcurrencyException as the number of rows affected is used to detect existing altered data.

like image 28
Jim Avatar answered Nov 19 '22 08:11

Jim