Strange object update in Entity Framework Code-First

I solve the problem with updating the object before saving to the database and getting strange behavior.

I am using Entity Framework 4.1 Code-First in an ASP.NET MVC 3 web application. Here is a 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 must be copied for RentPrice when creating it. The car is selected by the user, so initially Order.RentPrice is 0.

Here I want to copy the 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 does not work due to an error on SaveChanges that the object has validation errors. OK. I found that you first need to call UpdateModel(order); and then change the values.

So what I have. Work 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(); 

Work code (!):

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

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

Update

I get a DbEntityValidationException : "Failed to validate for one or more objects. See more details" EntityValidationErrors property. "From an internal exception:" OriginalValues ​​cannot be used for objects in the added state. "

+6
source share
5 answers

When you get

"Failed to validate for one or more objects. EntityValidationErrors property for more information. Exception:" OriginalValues ​​cannot be used for objects in the Added state. "

This means that there were errors, such as NOT NULL collumns, which were empty or other restrictions, checked entity verification errors by debugging or something 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 ); } } } 
+18
source

OriginalValues ​​cannot be used for objects in the added state.

You can fix it by indicating that the non identity fields of the primary keys are indicated 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-evident when you have a context, but otherwise it makes you think. The database generates two statements to insert, the second of which:

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

This statement will not return rows for non-identity columns. Consequently, OriginalValues will remain unchanged in the added state. This also explains why this exception is wrapped in an OptimisticConcurrencyException , since the number of rows affected is used to detect existing modified data.

+1
source

Have you declared a primary key anywhere? You must do this using a FluentAPI or attribute similar to this:

 public class Order { [Key] 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 { [Key] 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; } } 

Or in your Context, you can use the Fluent API to declare a key, for example

 builder.Entity<Car>().HasKey(x=>x.CarId); builder.Entity<Order>().HasKey(x=>x.OrderId); 
0
source

I have an idea, but this is more of a hunch ... Maybe by the time you enter this Create function, the context already knows about this Horde? If so, attempting to re-add again may result in this error.

In your last part of the code (the one that works amazingly), did you try to use the var intermediate variable without casting to double?

I am also intrigued by this UpdateModel ... I use EF, but not MVC, so maybe this has nothing to do with it, but if it's a user-defined function, what does it do?

0
source

I am sure that the problem would be fixed many centuries ago, I just wanted to pay my 2 cents.

I also ran into a problem with the same error message, I used Oracle and EF 5.0. Finally, I got a solution by spending more than 12 hours.

For me, there was a lack of permissions for the user in the table where I tried to insert the values, and in the error message there were no hints of the actual resolution problem, which was really strange.

Hope someone finds this helpful and doesn't spend hours, like me, troubleshooting.

Greetings

Avi

0
source

Source: https://habr.com/ru/post/895345/


All Articles