la combinación de dos campos debe ser única en el primer enfoque del código de Entity Framework. ¿Cómo sería?

Tengo dos contactos de clase y grupos

La combinación de FirstName y LastName debe ser única y puede agregar varias direcciones para un único contacto. ¿Cómo puedo hacer esto en el primer enfoque del código del marco de entidades?

 public class Contacts { [Key] public int ContactID { get; set; } [ForeignKey("Group")] public int GroupID { get; set; } [Required] public string FirstName { get; set; } [Required] public string LastName { get; set; } [Required] public string Address { get; set; } [Required] public string Number { get; set; } [Required] [EmailAddress] public string EmailId { get; set; } [DataType(DataType.Date)] public DateTime CreateDate { get; set; } public DateTime? ModifiedDate { get; set; } public virtual Groups Group { get; set; } } public class Groups { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int GroupID { get; set; } [Required] public string GroupName { get; set; } [Required] public string GroupDiscription { get; set; } public DateTime CreateDate { get; set; } public DateTime ModifiedDate { get; set; } } 

La verificación de duplicados significa que debe ir a la base de datos para validar. En Entity Framework Code First, eso significa usar DbContext. Consulte la Implementación de la validación en el contexto con ValidateEntity para obtener una gran explicación de cómo validar en Entity Framework.

Debe anular el método ValidateEntity en su clase de contexto:

  protected override DbEntityValidationResult ValidateEntity( DbEntityEntry entityEntry, IDictionary items) { //base validation for Data Annotations, IValidatableObject var result = base.ValidateEntity(entityEntry, items); //You can choose to bail out before custom validation //if (result.IsValid) // return result; CustomValidate(result); return result; } private void CustomValidate(DbEntityValidationResult result) { ValidateContacts(result); ValidateOrganisation(result); } private void ValidateContacts(DbEntityValidationResult result) { var c = result.Entry.Entity as Contact; if (c== null) return; if (Contacts.Any(a => a.FirstName == c.FirstName && a.LastName == c.LastName && a.ID != c.ID)) result.ValidationErrors.Add( new DbValidationError("Name", "Name already exists")); } private void ValidateOrganisation(DbEntityValidationResult result) { var organisation = result.Entry.Entity as Organisation; if (organisation == null) return; if (Organisations.Any(o => o.Name == organisation.Name && o.ID != organisation.ID)) result.ValidationErrors.Add( new DbValidationError("Name", "Name already exists")); } 

Esta validación se activa cuando hay una llamada a SaveChanges . Si hay algún error, se lanza una DbEntityValidationException .

Más sobre la validación de estructuración aquí

Para un enfoque de “cinturón y abrazaderas”, también agrego índices únicos a la base de datos en mis claves naturales: en una migración. De este modo, se evitan datos no válidos debido a las inserciones en la base de datos que no pasan por Entity Framework:

 public partial class Adduniqueindexes : DbMigration { public override void Up() { //You have to use Sql if the column is nullable: Sql(@"CREATE UNIQUE INDEX IX_UPRN ON Properties(UPRN, OrganisationID) WHERE UPRN IS NOT NULL")); CreateIndex("dbo.Organisations", "Name", unique: true, name: "IX_NaturalKey"); CreateIndex("dbo.Contacts", new string[] { "FirstName", "LastName" }, unique: true, name: "IX_NaturalKey"); } public override void Down() { DropIndex("dbo.Properties", "IX_UPRN"); DropIndex("dbo.Organisations", "IX_NaturalKey"); DropIndex("dbo.Contacts", "IX_NaturalKey"); } } 

Más sobre los índices aquí

Nota adicional A partir de EF6.1, es posible indicar que se debe crear un índice en un campo agregando un atributo de datos:

 [Index("IX_NaturalKey", IsUnique = true)] [Required] //If the field is nullable then you have to create the index in the migration //using sql, so I'd only expect IsUnique = true on a Required field [StringLength(256)] //indexes must be less than 900 bytes in Sql Server, //so nvarchar(max) will not do public string Name{ get; set; } 

No hay soporte mágico para esto en Entity Framework. Tendrás que hacer esto manualmente. Primero compruebe si el contacto en un lote tiene nombres únicos. Luego, verifique si existe alguna combinación de FirstName/LastName en la base de datos.

Sin embargo, nunca va a ser una solución sólida, porque siempre habrá una latencia entre el cheque y el compromiso final con la base de datos. Entonces, como último guardián, debería agregar un índice de base de datos único en FirstName/LastName .