Entity Framework check for uniqueness before insert
Hi I have an Invoice
type like:
public class Invoice : IEntity, IValidatableObject
{
public virtual int Id { get; set; }
[Required(ErrorMessage = "Invoice Number is a required field.")]
[Display(Name = "Invoice Number:")]
public virtual string InvoiceNumber { get; set; }
[Required(ErrorMessage = "Invoice Date is a required field.")]
[Display(Name = "Invoice Date:")]
[DataType(DataType.Date)]
public DateTime? InvoiceDate { get; set; }
[Required(ErrorMessage = "Organisation is a required field.")]
[Display(Name = "Organisation:")]
public int OrganisationId { get; set; }
[Required(ErrorMessage = "Region is a required field.")]
[Display(Name = "Region:")]
public virtual int? AreaId { get; set; }
[Required(ErrorMessage = "Total (Exc. GST) is a required field.")]
[Display(Name = "Total (Exc. GST):")]
public decimal? TotalExcludingGst { get; set; }
[Required(ErrorMessage = "Total (Inc. GST) is a required field.")]
[Display(Name = "Total (Inc. GST):")]
public decimal? TotalIncludingGst { get; set; }
public virtual string CreatedByUserName { get; set; }
public virtual DateTime CreatedDateTime { get; set; }
public virtual string LastModifiedByUserName { get; set; }
public virtual DateTime? LastModifiedDateTime { get; set; }
// Navigation properties
public virtual Area Area { get; set; }
public virtual Organisation Organisation { get; set; }
public virtual ICollection<InvoiceLine> InvoiceLines { get; set; }
#region IValidatableObject Members
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if ((TotalExcludingGst + (TotalExcludingGst * .15m)) != TotalIncludingGst) {
yield return new ValidationResult("The total (exc. Gst) + Gst does not equal the total (inc. Gst).");
}
}
#endregion
What I want to do is make sure on insert update that the combination of Organsation
and InvoiceNumber
is unique.
I'm considering something like:
public IEnumerable<ValidationResult> Validate(Valid开发者_如何学GoationContext validationContext)
{
var repository = new Repository<Invoice>();
if(!repositoy.CheckUnique(Id)) {
yield return new ValidationResult("The combination of Organisation and Invoice number is already in use");
}
}
Is this bad practise? To be instantiating the repository inside the model?
Is there a better way?
Your solution is not work correctly in a multi user scenario. Because between checking whether an ID
exists and saving changes another record maybe inserted with that same ID
.
You can create a Unique Constraint
on your table. This is the safe way to ensure duplicates are not created.
Current versions of EF does not model/support Unique Constraint
s. However what you can do is catch the specific exception and check the error message. Then show the errors
try
{
//updation logic
context.SaveChanges();
}
catch (System.Data.DataException de)
{
Exception innerException = de;
while (innerException.InnerException != null)
{
innerException = innerException.InnerException;
}
if (innerException.Message.Contains("Unique_constraint_name"))
{
ModelState.AddModelError(string.Empty, "Error Message");
return;
}
ModelState.AddModelError(string.Empty, "Error Message");
return View();
}
If you are using ASP.NET Web forms you can check this answer
精彩评论