2015-10-01 16 views
19

Tôi sử dụng mã EF 6.1.x trước.Chỉ mục bộ lọc khung thực thể

Tôi đã đọc rằng chỉ mục có biểu thức lọc không được EF hỗ trợ mới nhất.

Ngoài ra còn có không có giải pháp trên SO:

EF 6.1 Unique Nullable Index

Một năm sau đó, cách làm việc để thực hiện một công việc Index Lọc với Mã Trước DbMigrations là gì?

CREATE UNIQUE NONCLUSTERED INDEX [IX_DefaultLanguageApplicationId] ON [dbo].[Languages] 
(
    [IsDefaultLanguage] ASC, 
    [ApplicationId] ASC, 
) 
WHERE ([IsDefaultLanguage]=(1)) 
+0

Bài viết thú vị: http://stackoverflow.com/questions/29922099/how-to-add-an-index-on-multiple-columns-with-asc-desc-sort-using-the-fluent-api – Elisabeth

Trả lời

20

Trong EF 6.1, cách làm việc để làm công việc này với Mã Trước DbMigrations là sử dụng phương pháp Sql trong lớp DbMigration:

public partial class AddIndexes : DbMigration 
{ 
    public override void Up() 
    { 
     Sql(@"CREATE UNIQUE NONCLUSTERED INDEX 
      [IX_DefaultLanguageApplicationId] ON [dbo].[Languages] 
      (
       [IsDefaultLanguage] ASC, 
       [ApplicationId] ASC 
      ) 
      WHERE ([IsDefaultLanguage]=(1))"); 

    } 

    public override void Down() 
    { 
     DropIndex("dbo.Languages", "IX_DefaultLanguageApplicationId"); 
    } 
} 

Nhưng tôi nhận ra rằng bạn có lẽ hỏi nếu bạn có thể create an index using the IndexAttribute introduced in 6.1, nhưng với một Lọc - câu trả lời cho đó là "Không"

Gần một bản sao của: Entity Framework 6.1 - Create index with INCLUDE statement

+0

Có Tôi đang tìm http://blog.oneunicorn.com/2014/02/15/ef-6-1-creating-indexes-with-indexattribute/ NHƯNG tôi biết thực sự nó không thể được nêu ra. Vẫn cảm ơn! – Elisabeth

+0

tôi đã thêm lớp này một phần và đã làm "cập nhật cơ sở dữ liệu" sau đó tất cả các di chuyển đã được áp dụng một cách rõ ràng NHƯNG chỉ mục mới này không được tạo ra trong cơ sở dữ liệu ??? – Elisabeth

+0

Ok Tôi đã tạo ra một migratin rỗng đầu tiên NHƯNG sau đó tôi nhận được lỗi này: Mã lỗi: 102, Tiểu bang: 1, Loại: 15 Cú pháp không chính xác gần ')'. Bạn vui lòng sửa lỗi ")"? – Elisabeth

1

Tôi biết rằng bài viết gốc đề cập đến phiên bản 6.1 của EF, nhưng sau một số nghiên cứu tôi đã tìm thấy cách thêm phương pháp mở rộng cho các chỉ mục được lọc vào api thông thạo EF Core (phiên bản 1.1). Có lẽ ai đó sẽ tìm thấy điều này hữu ích (và có thể có một cách để thực hiện điều này cũng trong các phiên bản cũ). Tôi phải cảnh báo bạn. Vì giải pháp này sử dụng các lớp từ trong các không gian tên Microsoft.EntityFrameworkCore.Migrations.InternalMicrosoft.EntityFrameworkCore.Infrastructure nên không đảm bảo rằng mã này sẽ hoạt động sau khi EF được cập nhật. Có một bản tóm tắt của mỗi lớp trong các không gian tên này nói rằng

This API may change or be removed in future releases

, vì vậy bạn đã được cảnh báo.

Nhưng đến thời điểm này.

Trước tiên, bạn phải tạo phương pháp mở rộng chuẩn cho IndexBuilder. Trách nhiệm chính của nó là thêm một chú thích mới với điều kiện vào chỉ mục được xây dựng. Người ta sẽ sử dụng phương pháp này sau đó với api thông thạo. Lest gọi chú thích của chúng tôi SqlServer:FilteredIndex.

static class FilteredIndexExtension 
{ 
    public static IndexBuilder Filtered(this IndexBuilder indexBuilder, string condition) 
    { 
     indexBuilder.HasAnnotation("SqlServer:FilteredIndex", condition); 

     return indexBuilder; 
    } 
} 

Tiếp theo, bạn phải cho phép chú thích này thực sự được đưa vào bên trong di chuyển. Bạn phải ghi đè hành vi mặc định của SqlServerMigrationsAnnotationProvider đối với người xây dựng chỉ mục.

class ExtendedSqlServerMigrationsAnnotationProvider : SqlServerMigrationsAnnotationProvider 
{ 
    public override IEnumerable<IAnnotation> For(IIndex index) 
    { 
     var baseAnnotations = base.For(index); 
     var customAnnotatinos = index.GetAnnotations().Where(a => a.Name == "SqlServer:FilteredIndex"); 

     return baseAnnotations.Concat(customAnnotatinos); 
    } 
} 

Bây giờ đến phần khó nhất. Chúng tôi phải ghi đè hành vi mặc định của SqlServerMigrationsSqlGenerator liên quan đến chỉ mục.

class ExtendedSqlServerMigrationsSqlGenerator : SqlServerMigrationsSqlGenerator 
{ 
    public ExtendedSqlServerMigrationsSqlGenerator(IRelationalCommandBuilderFactory commandBuilderFactory, ISqlGenerationHelper sqlGenerationHelper, IRelationalTypeMapper typeMapper, IRelationalAnnotationProvider annotations, IMigrationsAnnotationProvider migrationsAnnotations) : base(commandBuilderFactory, sqlGenerationHelper, typeMapper, annotations, migrationsAnnotations) 
    { 
    } 

    protected override void Generate(CreateIndexOperation operation, IModel model, MigrationCommandListBuilder builder, bool terminate) 
    { 
     base.Generate(operation, model, builder, false); 

     var filteredIndexCondition = operation.FindAnnotation("SqlServer:FilteredIndex"); 

     if (filteredIndexCondition != null) 
      builder.Append($" WHERE {filteredIndexCondition.Value}"); 

     if (terminate) 
     { 
      builder.AppendLine(SqlGenerationHelper.StatementTerminator); 
      EndStatement(builder); 
     } 
    } 
} 

Như bạn có thể thấy, chúng tôi đang kêu gọi các máy phát điện cơ sở ở đây, vì vậy tình trạng của chúng tôi sẽ được thêm vào ở phần cuối của nó mà không thay đổi nó. Chúng ta phải nhớ là không chấm dứt câu lệnh SQL cơ sở ở đây (đối số cuối cùng được truyền cho phương thức base.Generatefalse). Nếu chú thích của chúng ta được thiết lập, chúng ta có thể gắn thêm giá trị của nó sau mệnh đề WHERE ở cuối câu lệnh SQL. Sau đó, tùy thuộc vào đối số được truyền cho phương thức này, cuối cùng chúng ta có thể chấm dứt câu lệnh hoặc để nguyên nó.

Để tất cả các bộ phận đó hoạt động, chúng tôi phải thay thế các dịch vụ cũ bằng phiên bản mới của chúng bằng cách ghi đè phương pháp OnConfiguring của chúng tôi DbContext.

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 
    { 
     optionsBuilder.ReplaceService<SqlServerMigrationsAnnotationProvider, ExtendedSqlServerMigrationsAnnotationProvider>(); 
     optionsBuilder.ReplaceService<SqlServerMigrationsSqlGenerator, ExtendedSqlServerMigrationsSqlGenerator>(); 
    } 

Bây giờ chúng ta có thể sử dụng phương pháp mở rộng của chúng tôi như thế này:

builder.HasIndex(a => a.Identity).IsUnique().Filtered("[End] IS NULL"); 

Nó sẽ tạo di cư như thế này:

migrationBuilder.CreateIndex(
      name: "IX_Activities_Identity", 
      table: "Activities", 
      column: "Identity", 
      unique: true) 
      .Annotation("SqlServer:FilteredIndex", "[End] IS NULL"); 

Và sau khi gọi Script-Migration commad trong Package Manager Console chúng ta sẽ thấy một kết quả SQL như sau:

CREATE UNIQUE INDEX [IX_Activities_Identity] ON [Activities] ([Identity]) WHERE [End] IS NULL; 

Phương pháp này thực sự có thể được sử dụng để bao gồm bất kỳ trình tạo SQL tùy chỉnh nào vào api lõi thông thạo ef. Ít nhất là miễn là API EF vẫn giữ nguyên.

Các vấn đề liên quan