简体   繁体   English

EF Core - 索引中的导航属性

[英]EF Core - navigational property in index

I have the following two classes 我有以下两个班级

public class Tip
{
    public string Home { get; set; }
    public string Away { get; set; }
    public string Prediction { get; set; }
    public Tipster Tipster { get; set; }
    ... other properties
}


public class Tipster
{
    public int Id { get; set; }
    public string Username { get; set; }
    public string Platform { get; set; }
}

Now, I want to make unique index in theTip table. 现在,我想在theTip表中创建唯一索引。 According to the EF Core documentation, there is no Data Annotations syntax, so I am using the fluent one: 根据EF Core文档,没有Data Annotations语法,所以我使用流利的语法:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Tip>()
            .HasIndex(entity => new { entity.Tipster, entity.Home, entity.Away, entity.Prediction })
            .HasName("IX_UniqueTip")
            .IsUnique();
    }

Now, when I update the database I get the following error 现在,当我更新数据库时,我收到以下错误

C:..>dotnet ef database update System.InvalidOperationException: Cannot call Property for the property 'Tipster' on entity type 'Tip' because it is configured as a navigation property. C:..> dotnet ef数据库更新System.InvalidOperationException:无法在实体类型'Tip'上为属性'Tipster'调用Property,因为它被配置为导航属性。 Property can only be used to configure scalar properties. 属性只能用于配置标量属性。

It seems that EF didn't liked the fact that I am using referential property in the index. 似乎EF不喜欢我在索引中使用引用属性的事实。 How can I fix that ? 我该如何解决这个问题?

You can't use navigation property in index defining expression. 您不能在索引定义表达式中使用导航属性。 Instead, you should use the corresponding FK property. 相反,您应该使用相应的FK属性。

The problem in your case is that you don't have explicit FK property in your model Tip . 在您的情况下,问题是您的模型Tip没有明确的FK属性。 By convention EF Core will create int? TipsterId 按照惯例,EF Core会创建int? TipsterId int? TipsterId shadow property . int? TipsterId 影子属性 So theoretically you should be able to use EF.Property method to access it: 所以理论上你应该能够使用EF.Property方法来访问它:

.HasIndex(e => new { TipsterId = EF.Property<int>(e, "TipsterId"), e.Home, e.Away, e.Prediction })

Unfortunately this doesn't work currently (EF Core 2.0.1). 不幸的是,这当前不起作用(EF Core 2.0.1)。 So you have to resort to HasIndex overload with params string[] propertyNames : 所以你必须使用params string[] propertyNames来使用HasIndex重载:

.HasIndex("TipsterId", nameof(Tip.Home), nameof(Tip.Away), nameof(Tip.Prediction))

They way you defined your entities EF will put the referential column into the tipster table, since it looks like a 1-n relationship. 他们定义你的实体的方式EF会将引用列放入tipster表中,因为它看起来像1-n关系。 Meaning a tipster can place several tips, but each tip is only placed by a single tipster. 这意味着一个推特可以提供几个提示,但每个提示只能由一个推特放置。

That means on the database level there is nothing to index. 这意味着在数据库级别上没有索引。 No column, no key - nothing. 没有专栏,没有钥匙 - 没什么。

To fix this you might ask yourself what you really want to achieve with an index in the first place. 要解决这个问题,您可能会问自己,您最初想要通过索引实现什么目标。 An index is supposed to make queries using the columns of the index faster and avoid a full table scan. 索引应该更快地使用索引的列进行查询,并避免全表扫描。

You must define the property TipsterId explicitly cause the Navigation property define it as shadow, so you cannot use it on custom index or alternate key 您必须明确定义属性TipsterId,导致Navigation属性将其定义为shadow,因此您无法在自定义索引或备用键上使用它

public class Tip
{
    public string Home { get; set; }
    public string Away { get; set; }
    public string Prediction { get; set; }

    public int TipsterId { get; set; }

    public Tipster Tipster { get; set; }
    ... other properties
}

Now you can 现在你可以

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Tip>()
        .HasIndex(entity => new { entity.TipsterId, entity.Home, entity.Away, entity.Prediction })
        .HasName("IX_UniqueTip")
        .IsUnique();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM