我想在多个列上放置索引(如this question中所述),但其中一个属性是导航属性,在模型中没有外键属性。
TL; DR 在底部。
我的模特:
public class User
{
public int Id { get; set; }
public string Email { get; set; }
public virtual Shop Shop { get; set; }
}
public class Shop
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Context : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Shop> Shops { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().HasRequired(u => u.Shop).WithMany();
modelBuilder.Entity<User>().Property(u => u.Email).HasMaxLength(256);
}
}
我使用扩展程序(基于上述问题):
internal static class ModelBuilderExtensions
{
public static StringPropertyConfiguration AddMultiColumnIndex(this StringPropertyConfiguration config, string indexName, int columnOrder, bool unique = false, bool clustered = false)
{
var indexAttribute = new IndexAttribute(indexName, columnOrder) { IsUnique = unique, IsClustered = clustered };
var indexAnnotation = new IndexAnnotation(indexAttribute);
return config.HasColumnAnnotation(IndexAnnotation.AnnotationName, indexAnnotation);
}
public static PrimitivePropertyConfiguration AddMultiColumnIndex(this PrimitivePropertyConfiguration property, string indexName, int columnOrder, bool unique = false, bool clustered = false)
{
var indexAttribute = new IndexAttribute(indexName, columnOrder) { IsUnique = unique, IsClustered = clustered };
var indexAnnotation = new IndexAnnotation(indexAttribute);
return property.HasColumnAnnotation(IndexAnnotation.AnnotationName, indexAnnotation);
}
}
我希望创建一个索引如下:
modelBuilder.Entity<User>().Property(x => x.Email).AddMultiColumnIndex("UX_User_EmailShopId", 0, unique: true);
modelBuilder.Entity<User>().Property(x => x.Shop.Id).AddMultiColumnIndex("UX_User_EmailShopId", 1, unique: true);
但是当脚手架迁移时,这会给我一个错误:
System.InvalidOperationException:“商店”类型已经存在 配置为实体类型。它不能被重新配置为复杂的 类型。
当我尝试按如下方式添加索引时,它会出现另一个错误:
modelBuilder.Entity<User>().Property(x => x.Shop).AddMultiColumnIndex("UX_User_EmailShopId", 1, unique: true);
“My.NameSpace.Shop”类型必须是非可空值类型 为了在泛型类型或方法中将其用作参数“T” “System.Data.Entity.ModelConfiguration.Configuration.StructuralTypeConfiguration.Property(System.Linq.Expressions.Expression&GT)
所以我的问题是,当我的模型中没有定义shop_id时(如果我不想定义它),如何在电子邮件和商店(id)组合上使用fluent-api添加索引? / p>
结果SQL应该类似于:
CREATE UNIQUE NONCLUSTERED INDEX [UX_User_EmailShopId] ON [dbo].[User]
(
[Email] ASC,
[Shop_Id] ASC
)
答案 0 :(得分:0)
使用C#和流利的语法,您必须做一些事情才能实现这一目标。
添加ShopId(用户类的外键.EF会理解这是Shop导航属性的外键,因此不再需要其他操作
public virtual Shop Shop { get; set; }
public int ShopId { get; set; }
在模型构建器index-config
中使用x.ShopIdmodelBuilder.Entity<User>().Property(x => x.ShopId).AddMultiColumnIndex("UX_User_EmailShopId", 1, unique: true);
在OnModelCreating中为User.Email属性配置添加MaxLength约束。这是因为index columns can max be 900 bytes和C#中的常规公共字符串转换为sql server中的varchar(max)。
modelBuilder.Entity<User>().Property(c => c.Email).HasMaxLength(255).AddMultiColumnIndex("UX_User_EmailShopId", 0, unique: true);;
所以你最终得到的是User类中的一个额外属性和dbcontext中的这个OnModelCreating方法:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().HasRequired(u => u.Shop).WithMany();
modelBuilder.Entity<User>().Property(x => x.Email).HasMaxLength(255).AddMultiColumnIndex("UX_User_EmailShopId", 0, unique: true);
modelBuilder.Entity<User>().Property(x => x.ShopId).AddMultiColumnIndex("UX_User_EmailShopId", 1, unique: true);
}
这些小改动将导致在SQL-server中创建此索引:
CREATE UNIQUE NONCLUSTERED INDEX [UX_User_EmailShopId]
ON [dbo].[Users]([Email] ASC, [ShopId] ASC);
或者使用迁移,而不想添加&#34; FK&#34;属性ShopId给你用户类,你可以在迁移UP方法中添加索引创建。
CreateIndex("Users", new[] { "Email", "ShopId" }, true, "UX_User_EmailShopId");
答案 1 :(得分:0)
TL&DR:如果你想在 FLUENT 模式中有多个索引,你可以执行以下操作:
You can now (EF core 2.1) use the fluent API as follows:
modelBuilder.Entity<ClassName>()
.HasIndex(a => new { a.Column1, a.Column2});
答案 2 :(得分:-1)
如果未在模型中定义shop_id,则无法使用fluent-api进行操作。
如果注意到,您正在使用DbModelBuilder,它是指模型,即代码中“定义”的模型。从代码到数据库,流利的API只有一种方法,而相反却没有。
仍然可以在不向模型添加shop_id的情况下创建索引,而是使用纯SQL而非流畅的API来创建索引
您可以使用注释来完成。您的User类需要像,但仅适用于EF 6.1
public class User
{
[Index("UX_User_EmailShopId", 1, IsUnique = true)]
public int Id { get; set; }
[Index("UX_User_EmailShopId", 2, IsUnique = true)]
public string Email { get; set; }
[Index("UX_User_EmailShopId", 3, IsUnique = true)]
public int ShopId { get; set; }
[ForeignKey("ShopId")]
public virtual Shop Shop { get; set; }
}