EF Core - 需要在代码优先应用程序中引用多对多联接表

问题描述 投票:0回答:1

我有一个地图应用程序,它将在地图上显示表示会员地址处的要素的图钉(例如,会员居住在纬度/经度“X”并与要素“Y”相关联)。 成员可以与多个功能关联,一个功能可以与多个成员关联(多对多)。 在我的 ASP.NET Core/EF Core 应用程序中,我创建了(代码优先)数据库,EF 创建了一个 FeatureMember 表,以使用 Member 和 Feature 表中的 MemberId 和 FeatureId 列来管理多对多关系。 到目前为止,一切正常 - 该应用程序完美地处理多对多关系。

现在,谈谈我遇到的映射问题。 在地图显示页面上,我向用户呈现了一个多选功能列表。 当用户更新地图时,JavaScript 捕获所选FeatureId(隐藏字段)的数组,然后Ajax 调用将该数组发送回Controller 和Repository 类。 一切都很好,直到我尝试构建查询以从数据库获取所需的映射信息。 我在 SSMS 中构建的查询(工作正常)连接到 EF Core 无法识别为实体的 FeatureMember 表。

编译器的错误消息是: CS1061:“MappingContext”不包含“FeatureMember”的定义,并且找不到接受“MappingContext”类型的第一个参数的可访问扩展方法“FeatureMember”(您是否缺少 using 指令或程序集引用?)

SSMS 中运行的 SQL 是:

SELECT
    m.MemberMailingName,a.AddressStreetNumber,a.AddressStreetName,a.AddressCity,a.AddressState,a.AddressZip,g.Latitude,g.Longitude,f.FeatureName
FROM
    Member m
JOIN MailAddress a ON m.MemberId = a.MemberId
JOIN FeatureMember fm ON m.MemberId = fm.MembersMemberId
JOIN Feature f ON f.FeatureId = fm.FeaturesFeatureId
JOIN Geography g ON g.MailAddressId = a.MailAddressId
WHERE
    f.FeatureId IN (1, 2)
ORDER BY f.FeatureId

我的 DbContext 类是:

namespace Mapping.Data
{
    public class MappingContext : DbContext
    {
        public MappingContext(DbContextOptions<MappingContext> options)
            : base(options)
        {
        }

        public DbSet<Mapping.Models.Member> Member { get; set; } = default!;
        public DbSet<Mapping.Models.Feature> Feature { get; set; } = default!;
        public DbSet<Mapping.Models.MailAddress> MailAddress { get; set; } = default!;
        public DbSet<Mapping.Models.Geography> Geography { get; set; } = default!;

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

            modelBuilder.Entity<Member>()
                .HasOne(a => a.MailAddress)
                .WithOne(m => m.Member);

            modelBuilder.Entity<Member>()
                .HasMany(f => f.Features)
                .WithMany(m => m.Members);

            modelBuilder.Entity<MailAddress>()
                .HasOne(g => g.Geography)
                .WithOne(a => a.MailAddress);
        }
    }
}
  • Member 表只有 Id、Name 和 Status 列
  • 功能表只有 Id、Name、Description 和 Status 列
  • MailAddress 表包含 Id、Address、City、State 和 Zip 列,其中 FK: MemberId
  • Geography 表包含 Id、Lat 和 Long 列以及 FK:MailAddressId
  • FeatureMember 表具有 FeaturesFeatureId 和 MembersMemberId 列,作为组合 PK 和 FK 返回到 Member 和 Feature 表

如何使用 EF Core/Linq 构建此查询?

asp.net-core entity-framework-core ef-code-first
1个回答
0
投票

EF 旨在接管根据对象模型自动为 Linq 查询生成 SQL 的责任。虽然它确实支持具有显式联接的显式 Linq QL,但使用它只是例外而不是常态。相反,利用对象模型中的导航属性并让 EF 生成合适的查询:

看看这个 SQL 以及我可以从你的实体对象模型中得到的内容:

SELECT
    m.MemberMailingName,a.AddressStreetNumber,a.AddressStreetName,a.AddressCity,a.AddressState,a.AddressZip,g.Latitude,g.Longitude,f.FeatureName
FROM
    Member m
JOIN MailAddress a ON m.MemberId = a.MemberId
JOIN FeatureMember fm ON m.MemberId = fm.MembersMemberId
JOIN Feature f ON f.FeatureId = fm.FeaturesFeatureId
JOIN Geography g ON g.MailAddressId = a.MailAddressId
WHERE
    f.FeatureId IN (1, 2)
ORDER BY f.FeatureId

...你应该从这样的事情中得到相同的结果:

int[] allowedFeatureIds = {1, 2};

var data = await _context.Members
    .Where(m => m.Features.Any(f => allowedFeatureIds.Contains(f.Id)))
    .SelectMany(m => m.Features.Select(f => new 
    {
        m.MemberMailingName,
        m.MailAddress.AddressStreetNumber,
        m.MailAddress.AddressStreetName,
        m.MailAddress.AddressCity,
        m.MailAddress.AddressState,
        m.MailAddress.AddressZip,
        m.MailAddress.Geography.Latitude,
        m.MailAddress.Geography.Longitude,
        f.FeatureName
    })).ToListAsync();

...假设您只想在代码中使用数据值。如果返回数据,请为这些内容构建 DTO 或视图模型类并填充它而不是匿名类型。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.