2

我有两个班级联系人和小组

FirstName和的组合LastName必须是唯一的,并且可以为单个联系人添加多个地址。我如何在实体框架代码优先方法中做到这一点?

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; }
}
4

2 回答 2

5

检查重复项意味着您必须去数据库进行验证。在 Entity Framework Code First 中,这意味着使用 DbContext。有关如何在 Entity Framework 中进行验证的详细说明,请参阅使用 ValidateEntity 在上下文中实现验证。

您应该在上下文类中覆盖 ValidateEntity 方法:

    protected override DbEntityValidationResult ValidateEntity(
                                        DbEntityEntry entityEntry, 
                                        IDictionary<object, object> 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"));
}

当调用 时会触发此验证SaveChanges。如果有任何错误,DbEntityValidationException则抛出 a。

更多关于结构验证的信息在这里

对于“带和大括号”方法,我还在我的自然键上向数据库添加唯一索引 - 在迁移中。从而防止由于不通过 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");
    }
}

更多关于索引的信息在这里

附加说明 从 EF6.1 开始,可以通过添加数据属性来指示应在字段上创建索引:

[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; }
于 2013-09-11T08:42:42.553 回答
1

在 Entity Framework 中没有对此的神奇支持。您必须手动执行此操作。首先检查一批中的联系人是否具有唯一名称。然后检查FirstName/LastName数据库中是否存在任何组合。

但是,这永远不会是一个健壮的解决方案,因为在检查和最终提交到数据库之间总会有延迟。因此,作为终极守卫,您确实应该在FirstName/LastName.

于 2013-09-10T16:22:46.850 回答