I have a web application (MVC 5, EntityFramework 6). It's connected to an SQL database via a DbContext. I'm having an issue where adding a new entity object creates a duplicate entry in the entity set (but not the DB) and I'm not sure how to stop this from happening.
Controller, whose method is called via an ajax request:
public class CustomerController : Controller
{
MyDBEntities db = new MyDBEntities(); //DbContext
public ActionResult SaveStuff(string customerId, string stuff)
{
Customer customer = db.Single(c => c.ID.Equals(customerId));
Stuff stuff = new Stuff(stuff, customer);
db.Stuffs.Add(stuff);
db.SaveChanges();
return PartialView("MyControl", customer);
}
}
There is a 1-to-many association between Customer and Stuff, and there is a "Stuffs" navigation property in Customer.
Stuff includes fields that are int, string, and DateTime.
The controller method returns a PartialView which is used by JavaScript to refresh the contents of a control.
The "MyControl" control does this:
var stuffs = Model.Stuffs.OrderByDescending(...);
When the control is rendered in this situation, Model.Stuffs
contains a duplicate entry. There's an entry with a name of Stuff
(probably the new object created in the control method) as well as well as an entry with a name of System.Data.Entity.DynamicProxies.Stuff_<uuid>
which is the same exact data (I imagine read from the DB).
This is only a problem when I'm writing into and then reading from an entity set within the same web request. Other/future web requests that cause a read are fine. How can I make this work correctly?
This is happening because the DateTime object is losing precision when it is written into the SQL database (see: SQL Server DateTime vs .NET DateTime). When read back from the DB, it has a different value and therefore does not overwrite the existing "stuff" object that still exists locally in db.Stuffs.
A simple solution is to change the DateTime's setter for Stuff to private and add your own pseudo-setter function that has the rounding built into it:
public void SetTimestamp(DateTime timestamp)
{
//Precision in SQL is lower than in .NET, so just round to tenth seconds
this.Updated = timestamp.AddTicks(- (timestamp.Ticks % (TimeSpan.TicksPerSecond / 10)));
}
Using DateTime2 in the SQL database (Server 2008+) is also an option should you need to maintain that level of precision.