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.Internal
và Microsoft.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.Generate
là false
). 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.
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