如何编写 EF Core Query 以过滤多个表?

bob*_*bob 4 c# entity-framework-core asp.net-core

将 ASP Core 2 与 EF Core 和 SQL Server 一起使用。我有,我认为检索给定分销商的制造商(或单个制造商)列表是一项简单的任务。

Users 表提供经过身份验证的用户,每个用户都与一个分销商相关联(在模型中表示为_user)。因此,当在GetManufacturers()上调用操作时ManufacturersController,它应该返回给定分销商的所有制造商。同样,GetManufacturers(int id)如果它与经过验证的分销商相关联,则应返回单个制造商。

表

为此,我正在尝试各种公式,例如:

await _context.Manufacturers
    .Include(a => a.Addresses)
    .Include(m => m.DistributorManufacturers)
    .Where (a => a.AddressesNavigation.State = "CA")
    .Where (m => m.Id == id)   // Manufacturers Id
    .Where (d => d.DistributorManufacturers.DistributorId == _user.DistributorId)
    .AsNoTracking()
    .ToListAsyc()
Run Code Online (Sandbox Code Playgroud)

VS 抱怨ICollection<DistributorManufacturers>不包含定义DistributorId(即使我从类中复制/粘贴了它)。它与我的地址过滤器在概念上没有区别。

我也尝试.ThenInclude添加分销商表,但没有运气。

DistributorManufacturers 表是使用 Scaffold-DbContext 创建的,并定义了外键和导航属性。

jpg*_*ssi 5

所以,做了一些工作来重新创建你的模型。我唯一改变的是我userId在分销商表中添加了,而不是相反的。这将是一个很长的答案..所以坚持下去

模型(省略 User 和 Address 实体,因为它们没有什么特别之处)

public abstract class Entity
{
    public int Id { get; set; }
}

public class Distributor : Entity
{   
    public User User { get; set; }

    public int UserId { get; set; }

    public Address Address { get; set; }

    public int AddressId { get; set; }

    public ICollection<DistributorManufacturer> DistributorManufacturers { get; set; }
}

public class Manufacturer : Entity
{
    public Address Address { get; set; }

    public int AddressId { get; set; }

    public ICollection<DistributorManufacturer> DistributorManufacturers { get; set; }
}

public class DistributorManufacturer
{
    public Distributor Distributor { get; set; }

    public int DistributorId { get; set; }

    public Manufacturer Manufacturer { get; set; }

    public int ManufacturerId { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

配置如下:

modelBuilder.Entity<Distributor>()
    .HasOne(p => p.User)
    .WithMany()
    .HasForeignKey(p => p.UserId);

modelBuilder.Entity<Distributor>()
    .HasOne(p => p.Address)
    .WithMany()
    .HasForeignKey(p => p.AddressId);

modelBuilder.Entity<Manufacturer>()
    .HasOne(p => p.Address)
    .WithMany()
    .HasForeignKey(p => p.AddressId);

// many to many mapping
modelBuilder.Entity<DistributorManufacturer>()
    .HasKey(bc => new { bc.DistributorId, bc.ManufacturerId });

modelBuilder.Entity<DistributorManufacturer>()
    .HasOne(bc => bc.Distributor)
    .WithMany(b => b.DistributorManufacturers)
    .HasForeignKey(bc => bc.DistributorId)
    .OnDelete(DeleteBehavior.Restrict);

modelBuilder.Entity<DistributorManufacturer>()
    .HasOne(bc => bc.Manufacturer)
    .WithMany(c => c.DistributorManufacturers)
    .HasForeignKey(bc => bc.ManufacturerId)
    .OnDelete(DeleteBehavior.Restrict);
Run Code Online (Sandbox Code Playgroud)

插入此值:

select * from Users
select * from Distributors
select * from Manufacturers
select * from DistributorManufacturers
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

然后,在GetManufacturers()您想要返回所有Manufacturers登录的操作中Distributor,AKA User。(这是我从你的问题中得出的假设。如果我错了,请纠正我)。所以,归结为查询:

// Simulate getting the Id of the logged in User.
var userId = 1;

var query = (from m in _context.Manufacturers
             join dm in _context.DistributorManufacturers on m.Id equals dm.ManufacturerId
             join dist in _context.Distributors on dm.DistributorId equals dist.Id
             join adrs in _context.Addresses on m.AddressId equals adrs.Id
             where dist.UserId == userId
             select new
             {
                 ManufacturerId = m.Id,
                 ManufacturerName = m.Name,
                 DistributorId = dist.Id,
                 DistributorName = dist.Name,
                 Address = adrs
             }).ToList();
Run Code Online (Sandbox Code Playgroud)

结果是这样:

[
    {
        "manufacturerId": 1,
        "manufacturerName": "Manufacturer 1",
        "distributorId": 1,
        "distributorName": "Distributor 1",
        "address": {
            "street": "Street 1",
            "city": "New York",
            "state": "NY",
            "id": 1
        }
    },
    {
        "manufacturerId": 2,
        "manufacturerName": "Manufacturer 2",
        "distributorId": 1,
        "distributorName": "Distributor 1",
        "address": {
            "street": "Street 2",
            "city": "New York",
            "state": "NY",
            "id": 2
        }
    }
]
Run Code Online (Sandbox Code Playgroud)

要使其GetManufacturers(int id)正常工作,只需将制造商 ID 添加到where子句中。由于它正在对 进行内部联接DistributorManufacturer,如果与登录用户没有关系,它将返回 null。

注意:在 EF Core 中,当您具有多对多关系时,您需要(至少现在......)将联合表作为一个实体。您可以在此处查看有关此问题的讨论:https : //github.com/aspnet/EntityFrameworkCore/issues/1368