使用EF Core 3.0生成的错误查询

时间:2019-11-11 09:32:36

标签: c# .net entity-framework-core

我正在尝试使用一个简单的where子句从SQL Server检索数据。但是,生成的查询不正确。此查询与EF Core 2.2完美配合,但与EF Core 3配合使用,则会引发异常。

    public async Task<List<CharacterReplacements>> GetReplacementsAsync(int? replacementSetId)
    {
        var replacementQuery = _context.CharacterReplacements.AsQueryable();

        if (replacementSetId.HasValue)
        {
            replacementQuery = replacementQuery.Where(r => r.CharacterReplacementSetID == replacementSetId.Value); // .AsQueryable();
        }

        var replacementList = await replacementQuery.ToListAsync();

        return replacementList;
    }

[Serializable]
[Table("CharacterReplacementSets", Schema = "SYSTEM")]
public class CharacterReplacementSets
{
    [NavigationPropertyKey]
    [Key]
    public int CharacterReplacementSetID { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public ICollection<CharacterReplacements> CharacterReplacements { get; set; }
    public ICollection<FormatField> FormatFields { get; set; }
    public string CreatedBy { get; set; }
    public DateTime CreatedOn { get; set; }
    public string UpdatedBy { get; set; }
    public DateTime? UpdatedOn { get; set; }
    public string DefaultEncoding { get; set; } // Default character set
    public string DefaultCharacter { get; set; }
    public CharacterReplacementSets()
    {
        CharacterReplacements = new List<CharacterReplacements>();
    }
}

[Serializable]
[Table("CharacterReplacements", Schema = "SYSTEM")]
public class CharacterReplacements
{
    [NavigationPropertyKey]
    [Key]
    public int CharacterReplacementID { get; set; }
    public char OriginalCharacter { get; set; }
    public string ReplacementCharacter { get; set; }
    public string CreatedBy { get; set; }
    public DateTime CreatedOn { get; set; }
    public string UpdatedBy { get; set; }
    public DateTime? UpdatedOn { get; set; }
    [ForeignKey("CharacterReplacementSets")]
    public int CharacterReplacementSetID { get; set; }
}

预期结果-检索所有characterReplacements,其中replaceSetId等于提供的replaceSetId。

实际结果- Microsoft.Data.SqlClient.SqlException:'无效的列名'CharacterReplacementSetsCharacterReplacementSetID'。

有人可以帮我吗?

1 个答案:

答案 0 :(得分:1)

问题不是特定的查询,而是模型映射。

首先,这里的ForeignKey属性

[ForeignKey("CharacterReplacementSets")]
public int CharacterReplacementSetID { get; set; }

无效。应用于导航属性时,应指定FK 属性名称。并按如下所示在FK属性上应用时,应指定导航属性名称。 CharacterReplacements没有名为CharacterReplacementSets的导航属性,因此该属性将被忽略。如果EF Core生成运行时错误来指示映射问题,那是很好的,但事实并非如此。

该属性在EF Core 1.x / 2.x中也被忽略。但是之所以起作用,是因为属性CharacterReplacementSetID的名称与CharacterReplacementSets的PK名称匹配。由于以下重大更改-The foreign key property convention no longer matches same name as the principal property,对于EF Core 3.0而言,情况不再如此。

因此,请删除不正确且具有误导性的ForeignKey属性,然后通过HasForeignKey流利的API(我更喜欢)配置FK属性:

modelBuilder.Entity<CharacterReplacementSets>()
    .HasMany(e => e.CharacterReplacements)
    .WithOne()
    .HasForeignKey(e => e.CharacterReplacementSetID);

或在导航属性上具有ForegnKey属性(或在没有导航属性时为反向导航属性):

[ForeignKey("CharacterReplacementSetID")]
public ICollection<CharacterReplacements> CharacterReplacements { get; set; }

请注意,FormatField和其他使用类似命名FK且没有导航属性的实体可能会遇到类似问题。

避免此问题的另一种方法是使用单个实体类名称,例如CharacterReplacementSetCharacterReplacement等,因为[entity name] + ID仍与EF Core约定匹配。通常,单单的类名是更好/更可取的,即使只是为了提高可读性。