Đặt ràng buộc duy nhất với API thông thạo?


184

Tôi đang cố gắng xây dựng một Thực thể EF với Mã đầu tiên và EntityTypeConfigurationsử dụng API thông thạo. việc tạo các khóa chính rất dễ dàng nhưng không phải vậy với một ràng buộc duy nhất. Tôi đã thấy các bài viết cũ đề nghị thực thi các lệnh SQL gốc cho việc này, nhưng điều đó dường như đánh bại mục đích. điều này có thể xảy ra với EF6 không?

Câu trả lời:


274

Trên EF6.2 , bạn có thể sử dụng HasIndex()để thêm các chỉ mục để di chuyển thông qua API thông thạo.

https://github.com/aspnet/EntityFramework6/issues/274

Thí dụ

modelBuilder
    .Entity<User>()
    .HasIndex(u => u.Email)
        .IsUnique();

Trên EF6.1 trở đi, bạn có thể sử dụng IndexAnnotation()để thêm các chỉ mục để di chuyển trong API thông thạo của mình.

http://msdn.microsoft.com/en-us/data/jj591617.aspx#Property Index

Bạn phải thêm tài liệu tham khảo vào:

using System.Data.Entity.Infrastructure.Annotations;

Ví dụ cơ bản

Đây là một cách sử dụng đơn giản, thêm một chỉ mục trên User.FirstNametài sản

modelBuilder 
    .Entity<User>() 
    .Property(t => t.FirstName) 
    .HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute()));

Ví dụ thực tế:

Dưới đây là một ví dụ thực tế hơn. Nó thêm một chỉ mục duy nhất trên nhiều thuộc tính: User.FirstNameUser.LastName, với tên chỉ mục "IX_FirstNameLastName"

modelBuilder 
    .Entity<User>() 
    .Property(t => t.FirstName) 
    .IsRequired()
    .HasMaxLength(60)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName, 
        new IndexAnnotation(
            new IndexAttribute("IX_FirstNameLastName", 1) { IsUnique = true }));

modelBuilder 
    .Entity<User>() 
    .Property(t => t.LastName) 
    .IsRequired()
    .HasMaxLength(60)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName, 
        new IndexAnnotation(
            new IndexAttribute("IX_FirstNameLastName", 2) { IsUnique = true }));

4
Điều này là bắt buộc để đặt tên chú thích cột là "Chỉ mục"! Tôi đã viết một cái tên khác và nó đã không hoạt động! Tôi đã dành hàng giờ trước khi tôi thử đổi tên nó thành "Index" ban đầu như trong bài viết của bạn và hiểu rằng điều này quan trọng. :( Phải có một hằng số cho nó trong khung để không cứng mã chuỗi.
Alexander Vasilyev

10
@AlexanderVasilyev Hằng số được định nghĩa làIndexAnnotation.AnnotationName
Nathan

3
@Nathan Cảm ơn bạn! Đó là nó! Ví dụ trong bài này phải được sửa bằng hằng số này.
Alexander Vasilyev

2
Dường như không thể tìm thấy nó trong EF7 - DNX
Shimmy Weitzhandler

2
Tôi tin rằng IsUnique cần phải được đặt thành đúng khi tạo IndexAttribution trong ví dụ đầu tiên. Như thế này : new IndexAttribute() { IsUnique = true }. Mặt khác, nó chỉ tạo ra chỉ mục thông thường (không duy nhất).
jakubka

134

Ngoài câu trả lời của Yorro, nó cũng có thể được thực hiện bằng cách sử dụng các thuộc tính.

Mẫu cho inttổ hợp phím duy nhất:

[Index("IX_UniqueKeyInt", IsUnique = true, Order = 1)]
public int UniqueKeyIntPart1 { get; set; }

[Index("IX_UniqueKeyInt", IsUnique = true, Order = 2)]
public int UniqueKeyIntPart2 { get; set; }

Nếu kiểu dữ liệu là string, thì MaxLengthphải thêm thuộc tính:

[Index("IX_UniqueKeyString", IsUnique = true, Order = 1)]
[MaxLength(50)]
public string UniqueKeyStringPart1 { get; set; }

[Index("IX_UniqueKeyString", IsUnique = true, Order = 2)]
[MaxLength(50)]
public string UniqueKeyStringPart2 { get; set; }

Nếu có mối quan tâm phân tách mô hình lưu trữ / miền, sử dụng Metadatatypethuộc tính / lớp có thể là một tùy chọn: https://msdn.microsoft.com/en-us/l Library / ff664465% 28v = ppp.50% 29.aspx? F = 255 & MSPPError = -2147217394


Một ví dụ ứng dụng bảng điều khiển nhanh:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;

namespace EFIndexTest
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var context = new AppDbContext())
            {
                var newUser = new User { UniqueKeyIntPart1 = 1, UniqueKeyIntPart2 = 1, UniqueKeyStringPart1 = "A", UniqueKeyStringPart2 = "A" };
                context.UserSet.Add(newUser);
                context.SaveChanges();
            }
        }
    }

    [MetadataType(typeof(UserMetadata))]
    public class User
    {
        public int Id { get; set; }
        public int UniqueKeyIntPart1 { get; set; }
        public int UniqueKeyIntPart2 { get; set; }
        public string UniqueKeyStringPart1 { get; set; }
        public string UniqueKeyStringPart2 { get; set; }
    }

    public class UserMetadata
    {
        [Index("IX_UniqueKeyInt", IsUnique = true, Order = 1)]
        public int UniqueKeyIntPart1 { get; set; }

        [Index("IX_UniqueKeyInt", IsUnique = true, Order = 2)]
        public int UniqueKeyIntPart2 { get; set; }

        [Index("IX_UniqueKeyString", IsUnique = true, Order = 1)]
        [MaxLength(50)]
        public string UniqueKeyStringPart1 { get; set; }

        [Index("IX_UniqueKeyString", IsUnique = true, Order = 2)]
        [MaxLength(50)]
        public string UniqueKeyStringPart2 { get; set; }
    }

    public class AppDbContext : DbContext
    {
        public virtual DbSet<User> UserSet { get; set; }
    }
}

45
Không phải nếu bạn muốn giữ cho mô hình miền của bạn tách biệt hoàn toàn với các mối quan tâm lưu trữ.
Rickard Liljeberg

4
Bạn cũng cần đảm bảo rằng bạn có một tài liệu tham khảo về
EntityFramework

2
Thật tuyệt nếu thuộc tính Index được tách ra khỏi Entity Framework để tôi có thể đưa nó vào dự án Mô hình của mình. Tôi hiểu rằng đó là một vấn đề lưu trữ, nhưng lý do chính tôi sử dụng nó là để đặt các ràng buộc duy nhất cho những thứ như Tên người dùng và Tên vai trò.
Sam

2
Dường như không thể tìm thấy nó trong EF7 - DNX
Shimmy Weitzhandler

4
Điều này chỉ hoạt động nếu bạn cũng hạn chế độ dài của chuỗi, vì SQL không cho phép nvarchar (max) được sử dụng làm khóa.
JMK

17

Đây là một phương pháp mở rộng để thiết lập các chỉ mục duy nhất trôi chảy hơn:

public static class MappingExtensions
{
    public static PrimitivePropertyConfiguration IsUnique(this PrimitivePropertyConfiguration configuration)
    {
        return configuration.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute { IsUnique = true }));
    }
}

Sử dụng:

modelBuilder 
    .Entity<Person>() 
    .Property(t => t.Name)
    .IsUnique();

Sẽ tạo di chuyển, chẳng hạn như:

public partial class Add_unique_index : DbMigration
{
    public override void Up()
    {
        CreateIndex("dbo.Person", "Name", unique: true);
    }

    public override void Down()
    {
        DropIndex("dbo.Person", new[] { "Name" });
    }
}

Src: Tạo chỉ mục duy nhất với API thông thạo Entity Framework 6.1


16

Câu trả lời của @ coni2k là chính xác tuy nhiên bạn phải thêm [StringLength]thuộc tính cho nó hoạt động nếu không bạn sẽ nhận được một ngoại lệ khóa không hợp lệ (Ví dụ dưới đây).

[StringLength(65)]
[Index("IX_FirstNameLastName", 1, IsUnique = true)]
public string FirstName { get; set; }

[StringLength(65)]
[Index("IX_FirstNameLastName", 2, IsUnique = true)]
public string LastName { get; set; }


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.