I have the following entity
public class DocumentHistory
{
public string Name { get; set; }
public string Description { get; set; }
public DateTime DateModified { get; set; }
public User ModifiedbyUser { get; set; }
public string HistoryAction { get; set; }
public virtual int DocumentId { get; set; }
public virtual Document Document { get; set; }
}
In my DbContext, I define the keys using:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// DocumentHistory properties
modelBuilder.Entity<DocumentHistory>()
.HasKey(x => new { x.DocumentId, x.DateModified });
}
In my automated integration tests, I initialize one record with
_doc.HistoryRecords.Add(new DocumentHistory { DateModified = DateTime.Now });
I then attempt to create a new record via:
// Create the history record
var history = new DocumentHistory
{
Name = doc.Name,
Description = doc.Description,
DateModified = DateTime.Now,
HistoryAction = ScrawlConstants.HistoryActions.Update,
ModifiedbyUser = user
};
doc.HistoryRecords.Add(history);
_context.SaveChanges();
When SaveChanges occurs, the following exception occurs:
System.Data.SqlServerCe.SqlCeException: A duplicate value cannot be inserted into a unique index. [ Table name = DocumentHistories,Constraint name = PK__DocumentHistories__000000000000006E ]
Theoretically, every record should be unique due to the difference in datetimes, but this isn’t the case. What am I doing wrong?
The accuracy of the clock on most machines is not high enough to produce a different value every time you read it.
Instead, on a typical system the accuracy is around 10-15ms. This means that consecutive reads of the clock within the same “window” will produce the exact same value.
See the DateTime.Now documentation for some information on this subject. Different sources of documentation gives different numbers but the relevant information is that it just isn’t accurate enough. One source stipulated 1/64th of a second, which translates to 15.625ms.
You should instead switch to something that is guaranteed to be unique, such as a Guid (though you lose the ordering property of the data) or use a server-generated identity key.