Entity Framework 5.0 Code First를 사용하고 있습니다.
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
어쨌든 그렇게 할 수 있습니까?
답변
Entity Framework 6.1을 사용하면 다음을 수행 할 수 있습니다.
[Index("IX_FirstAndSecond", 1, IsUnique = true)]
public int FirstColumn { get; set; }
[Index("IX_FirstAndSecond", 2, IsUnique = true)]
public int SecondColumn { get; set; }
속성의 두 번째 매개 변수는 색인에서 열 순서를 지정할 수있는 위치입니다.
추가 정보 : MSDN
답변
문제를 해결하는 세 가지 방법을 찾았습니다.
EntityFramework Core의 고유 인덱스 :
첫 번째 접근법 :
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Entity>()
.HasIndex(p => new {p.FirstColumn , p.SecondColumn}).IsUnique();
}
두 번째 접근법대체 키를 사용하여 EF Core로 고유 제약 조건을 만드는 입니다.
예
하나의 열 :
modelBuilder.Entity<Blog>().HasAlternateKey(c => c.SecondColumn).HasName("IX_SingeColumn");
여러 열 :
modelBuilder.Entity<Entity>().HasAlternateKey(c => new [] {c.FirstColumn, c.SecondColumn}).HasName("IX_MultipleColumns");
EF 6 이하 :
첫 번째 접근법 :
dbContext.Database.ExecuteSqlCommand(string.Format(
@"CREATE UNIQUE INDEX LX_{0} ON {0} ({1})",
"Entitys", "FirstColumn, SecondColumn"));
이 방법은 매우 빠르고 유용하지만 주된 문제는 Entity Framework가 이러한 변경 사항에 대해 아무것도 모른다는 것입니다!
두 번째 접근 방식 :
이 게시물에서 찾았지만 직접 시도하지 않았습니다.
CreateIndex("Entitys", new string[2] { "FirstColumn", "SecondColumn" },
true, "IX_Entitys");
이 방법의 문제점은 다음과 같습니다. DbMigration이 필요하므로없는 경우 어떻게해야합니까?
세 번째 접근 방식 :
이것이 가장 좋은 방법 이라고 생각하지만 시간이 좀 걸립니다. 나는 그 뒤에 아이디어를 보여줄 것입니다 :이 링크 http://code.msdn.microsoft.com/CSASPNETUniqueConstraintInE-d357224a
에서 고유 키 데이터 주석에 대한 코드를 찾을 수 있습니다 :
[UniqueKey] // Unique Key
public int FirstColumn { get; set;}
[UniqueKey] // Unique Key
public int SecondColumn { get; set;}
// The problem hier
1, 1 = OK
1 ,2 = NO OK 1 IS UNIQUE
이 접근법의 문제점; 어떻게 결합 할 수 있습니까? 이 Microsoft 구현을 확장하려는 아이디어가 있습니다.
[UniqueKey, 1] // Unique Key
public int FirstColumn { get; set;}
[UniqueKey ,1] // Unique Key
public int SecondColumn { get; set;}
나중에 Microsoft 예제에 설명 된대로 IDatabaseInitializer에서 지정된 정수에 따라 키를 결합 할 수 있습니다. 한 가지 주목할 점은 다음과 같습니다. 고유 속성이 문자열 유형 인 경우 MaxLength를 설정해야합니다.
답변
Code-First를 사용 하는 경우 사용자 정의 확장 HasUniqueIndexAnnotation을 구현할 수 있습니다.
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Infrastructure.Annotations;
using System.Data.Entity.ModelConfiguration.Configuration;
internal static class TypeConfigurationExtensions
{
public static PrimitivePropertyConfiguration HasUniqueIndexAnnotation(
this PrimitivePropertyConfiguration property,
string indexName,
int columnOrder)
{
var indexAttribute = new IndexAttribute(indexName, columnOrder) { IsUnique = true };
var indexAnnotation = new IndexAnnotation(indexAttribute);
return property.HasColumnAnnotation(IndexAnnotation.AnnotationName, indexAnnotation);
}
}
그런 다음 다음과 같이 사용하십시오.
this.Property(t => t.Email)
.HasColumnName("Email")
.HasMaxLength(250)
.IsRequired()
.HasUniqueIndexAnnotation("UQ_User_EmailPerApplication", 0);
this.Property(t => t.ApplicationId)
.HasColumnName("ApplicationId")
.HasUniqueIndexAnnotation("UQ_User_EmailPerApplication", 1);
이 마이그레이션 결과는 다음과 같습니다.
public override void Up()
{
CreateIndex("dbo.User", new[] { "Email", "ApplicationId" }, unique: true, name: "UQ_User_EmailPerApplication");
}
public override void Down()
{
DropIndex("dbo.User", "UQ_User_EmailPerApplication");
}
그리고 결국 데이터베이스에서 다음과 같이 끝납니다.
CREATE UNIQUE NONCLUSTERED INDEX [UQ_User_EmailPerApplication] ON [dbo].[User]
(
[Email] ASC,
[ApplicationId] ASC
)
답변
복합 키를 정의해야합니다.
데이터 주석을 사용하면 다음과 같습니다.
public class Entity
{
public string EntityId { get; set;}
[Key]
[Column(Order=0)]
public int FirstColumn { get; set;}
[Key]
[Column(Order=1)]
public int SecondColumn { get; set;}
}
다음을 지정하여 OnModelCreating을 재정의 할 때 modelBuilder로이를 수행 할 수도 있습니다.
modelBuilder.Entity<Entity>().HasKey(x => new { x.FirstColumn, x.SecondColumn });
답변
유창한 API를 사용하려면 사용자 정의 확장이 필요하다는 niaher의 답변은 작성 당시에 정확했을 수 있습니다. 이제 (EF core 2.1) 다음과 같이 유창한 API를 사용할 수 있습니다.
modelBuilder.Entity<ClassName>()
.HasIndex(a => new { a.Column1, a.Column2}).IsUnique();
답변
외래 키 와 함께 복합 인덱스 를 사용하기위한 @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 확장을 사용했습니다.
답변
@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; }
}