我使用实体框架5.0代码第一;

public class Entity
 {
   [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
   public string EntityId { get; set;}
   public int FirstColumn  { get; set;}
   public int SecondColumn  { get; set;}
 }

我想让FirstColumn和SecondColumn的组合是唯一的。

例子:

Id  FirstColumn  SecondColumn 
1       1              1       = OK
2       2              1       = OK
3       3              3       = OK
5       3              1       = THIS OK 
4       3              3       = GRRRRR! HERE ERROR

有办法吗?


当前回答

完成使用外键的复合索引的@chuck答案。

您需要定义一个属性来保存外键的值。然后可以在索引定义中使用此属性。

例如,我们有公司和员工,只有我们对任何员工(姓名,公司)有唯一的约束:

class Company
{
    public Guid Id { get; set; }
}

class Employee
{
    public Guid Id { get; set; }
    [Required]
    public String Name { get; set; }
    public Company Company  { get; set; }
    [Required]
    public Guid CompanyId { get; set; }
}

现在是Employee类的映射:

class EmployeeMap : EntityTypeConfiguration<Employee>
{
    public EmployeeMap ()
    {
        ToTable("Employee");

        Property(p => p.Id)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

        Property(p => p.Name)
            .HasUniqueIndexAnnotation("UK_Employee_Name_Company", 0);
        Property(p => p.CompanyId )
            .HasUniqueIndexAnnotation("UK_Employee_Name_Company", 1);
        HasRequired(p => p.Company)
            .WithMany()
            .HasForeignKey(p => p.CompanyId)
            .WillCascadeOnDelete(false);
    }
}

注意,我还为唯一的索引注释使用了@niaher扩展名。

其他回答

最近添加了一个组合键的唯一性2列使用'chuck'推荐的方法,谢谢@chuck。只有这条路在我看来比较干净:

public int groupId {get; set;}

[Index("IX_ClientGrouping", 1, IsUnique = true)]
public int ClientId { get; set; }

[Index("IX_ClientGrouping", 2, IsUnique = true)]
public int GroupName { get; set; }

对于那些在寻找2021年解决方案的人来说,公认答案的工作版本现在应该是这样的:

[Index(nameof(FirstColumn), nameof(SecondColumn), IsUnique = true)]
public class Entity
 {
   [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
   public string EntityId { get; set;}
   public int FirstColumn  { get; set;}
   public int SecondColumn  { get; set;}
 }

因此,注释应该存在于模型上,而不是单独的列上。还要注意nameof()语法。

这个答案来自于官方文档:https://learn.microsoft.com/en-us/ef/core/modeling/indexes?tabs=data-annotations

niaher关于使用fluent API需要自定义扩展的回答在撰写本文时可能是正确的。您现在可以(EF core 2.1)使用fluent API如下:

modelBuilder.Entity<ClassName>()
            .HasIndex(a => new { a.Column1, a.Column2}).IsUnique();

在@chuck接受的回答中,有一条评论说它在FK的情况下不起作用。

它为我工作,ef6.net4.7.2的情况下

public class OnCallDay
{
     public int Id { get; set; }
    //[Key]
    [Index("IX_OnCallDateEmployee", 1, IsUnique = true)]
    public DateTime Date { get; set; }
    [ForeignKey("Employee")]
    [Index("IX_OnCallDateEmployee", 2, IsUnique = true)]
    public string EmployeeId { get; set; }
    public virtual ApplicationUser Employee{ get; set; }
}

我想补充我的答案,因为提供的解决方案对我没有帮助。在我的例子中,其中一列是外键引用。

旧的模型:

public class Matrix
{
    public int ID { get; set; }

    public MachineData MachineData { get; set; }

    public MachineVariant MachineVariant { get; set; }
}

注意,MachineVariant是一个enum, MachineData是一个引用。

尝试使用@Bassam Alugili提供的解决方案:

modelBuilder.Entity<Matrix>()
   .HasIndex(sm => new { sm.MachineData, sm.DoughVariant }).IsUnique(true);

没有工作。所以我为machineData外键添加了一个ID列,如下所示:

public class Matrix
{
    public int ID { get; set; }

    public MachineData MachineData { get; set; }

    [ForeignKey("MachineData")]
    public int MachineDataID { get; set; }

    public MachineVariant MachineVariant { get; set; }
}

并将模型构建器代码更改为:

modelBuilder.Entity<Matrix>()
   .HasIndex(sm => new { sm.MachineDataID, sm.DoughVariant }).IsUnique(true);

哪一种方法得到了想要的解决方案