【问题标题】:Unable to query over many-to-many relationship无法查询多对多关系
【发布时间】:2017-03-15 18:54:19
【问题描述】:

有人知道如何在 EF Core 中查询 DB 的多对多关系,但更像是从一侧的左外连接?

让我解释一下我的意思。

Currency.cs

public class Currency
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid UID { get; set; } = Guid.NewGuid();

    public string   ISOCode { get; set; }

    public string   Symbol  { get; set; }

    [JsonIgnore]
    public List<RegionCurrency> RegionCurrencies { get; set; }
}

RegionCurrency.cs

public class RegionCurrency
{
    public Guid CurrencyUID { get; set; }

    public Guid RegionUID { get; set; }

    [ForeignKey("CurrencyUID")]
    public Currency Currency { get; set; }

    [ForeignKey("RegionUID")]
    public Region Region { get; set; }
}

Region.cs

public class Region
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid     UID { get; set; } = Guid.NewGuid();

    [StringLength(8)]
    public string CountryISOCode         { get; set; }

    public List<RegionCurrency> RegionCurrencies { get; set; }
}

MyContext.cs

public class LookupTablesContext : DbContext
{
    public virtual DbSet<Currency> Currecies { get; set; }

    public virtual DbSet<RegionCurrency> RegionCurrency { get; set; }

    public virtual DbSet<Region> Regions { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.HasDefaultSchema(SchemaName);

        modelBuilder.Entity<RegionCurrency>()
            .HasKey(t => new { t.CurrencyUID, t.RegionUID })
            .HasName("PK_RegionCurrency");

        modelBuilder.Entity<RegionCurrency>()
            .HasOne(pt => pt.Region)
            .WithMany(p => p.RegionCurrencies)
            .HasForeignKey(pt => pt.RegionUID);

        modelBuilder.Entity<RegionCurrency>()
            .HasOne(pt => pt.Currency)
            .WithMany(p => p.RegionCurrencies)
            .HasForeignKey(pt => pt.CurrencyUID);

        modelBuilder.Entity<Currency>()
            .HasIndex(c => c.ISOCode)
            .HasName("UX_Currency_ISOCode")
            .IsUnique();

        modelBuilder.Entity<Region>()
            .HasIndex(c => c.CountryISOCode)
            .HasName("UX_Region_CountryISOCode")
            .IsUnique();
    }
}

我的查询:

var result = ctx.Currencies
                  .Include(c => c.RegionCurrencies)
                  .ThenInclude(rc => rc.Select(rcs => rcs.Regions)) // This seems to be wrong
            .SingleOrDefault(c => c.ISOCode == "EUR");

我也尝试使用包含,如下图所示:

请注意,RegionCurrency 表可以包含 0-N 关系,即使 RegionCurrency 表中没有记录,我也想获取 Currency 实体。

这个(和类似的尝试)以这样的异常结束:

Microsoft.EntityFrameworkCore.dll 中出现“System.ArgumentException”类型的异常,但未在用户代码中处理

附加信息:属性表达式 'rc => {from RegionCurrency rc in rcs select [pts].Regions}' 无效。该表达式应表示属性访问:'t => t.MyProperty'。有关包含相关数据的更多信息,请参阅http://go.microsoft.com/fwlink/?LinkID=746393

Dependencies:
"Microsoft.EntityFrameworkCore": "1.0.1",
"Microsoft.EntityFrameworkCore.SqlServer": "1.0.1",

我找不到任何工作示例。但可以肯定的是,我只是个盲人。

感谢您的帮助。

【问题讨论】:

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


    【解决方案1】:

    如下图所示。

    var tag = ctx.Tags.Include(t => t.PostTags)
                 .ThenInclude(p => p.Post).FirstOrDefault(d => d.TagId == "2");
    
    var posts = tag.PostTags.Select(c => c.Post).ToList();
    

    注意: 有时 VS 无法正确显示智能感知。所以要小心智能感知:D。一种解决方案可能是:关闭 VS 并启动它的新实例。

    例如: intellisense 可以很好地处理这个.Include(t =&gt; t.PostTags)。但是要小心这个.ThenInclude(p =&gt; p.Post)。你必须在不依赖intellisense 的情况下编写它。希望微软将在 VS 的未来版本中解决此问题。

    结果:

    tag 的值:

    posts 的值:

    测试数据:

    更新:

    它正在工作。请查看代码。

    var currency = db.Currecies.Include(t => t.RegionCurrencies)
                               .ThenInclude(p => p.Region)   
                               .FirstOrDefault(t => t.UID == Guid.Parse("0f8fad5b-d9cb-469f-a165-70867728950e"));
    
    var regions = currency.RegionCurrencies.Select(c => c.Region).ToList();
    

    结果:

    currency 的值:

    regions 的值:

    Git 仓库: EfCoreManyToMany

    【讨论】:

    • 很抱歉,这行不通。我假设 Include(t => t.PostTags) 将返回 IIncludableQueriable>,因此 ThenInclude 将没有 p.Post 属性,但只有 List 方法,因为 List 类型将打开第一个包含的输出。
    • 感谢您更新您的答案。请查看我更新的问题(图片)。这是一个真实项目的屏幕截图,其中关系的定义方式与示例项目相同。
    • 我已经给出了 EF 核心文档示例的解决方案。现在您正在显示不同的代码集。那么您必须显示所有模型代码等...
    • 好的,当定义等于公共样本时,我不想提出这么长的问题......但是当你认为有必要时......我会这样做。
    • 更新为真实项目代码。希望这会有所帮助。
    猜你喜欢
    • 2022-01-15
    • 2019-07-24
    • 2021-10-03
    • 2018-11-02
    • 2015-10-26
    • 2011-08-08
    • 2015-05-29
    • 2019-10-28
    • 2019-01-31
    相关资源
    最近更新 更多