将 ASP Core 2 与 EF Core 和 SQL Server 结合使用。我有一个我认为是检索给定分销商的制造商(或个别制造商)列表的简单任务。
Users 表提供经过身份验证的用户,每个用户都与一个分销商相关联(在模型中表示为 _user
)。所以,当 Action 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()
VS 提示 ICollection<DistributorManufacturers>
不包含 DistributorId
的定义(即使我从类里面复制/粘贴了它)。它在概念上与我的地址过滤器没有区别。
我也试过 .ThenInclude
添加 Distributors 表,但没有成功。
DistributorManufacturers 表是使用 Scaffold-DbContext 创建的,并定义了外键和导航属性。
最佳答案
因此,做了一些工作来重新创建您的模型。我唯一改变的是我在 Distributor 表中添加了 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; }
}
配置如下:
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);
插入这个值:
select * from Users
select * from Distributors
select * from Manufacturers
select * from DistributorManufacturers
然后,在 GetManufacturers()
操作中,您想要为登录的 Distributor
返回所有 Manufacturers
,也就是 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();
结果是:
[
{
"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
}
}
]
要使 GetManufacturers(int id)
正常工作,只需将 Manufacturer Id 添加到 where
子句中。由于它在 DistributorManufacturer
上执行内部联接,如果与登录用户没有任何关系,它将返回 null。
注意:在 EF Core 中,当您拥有多对多关系时,您需要(至少现在……)将联合表作为一个实体。您可以在此处查看有关此的讨论:https://github.com/aspnet/EntityFrameworkCore/issues/1368
关于c# - 如何编写 EF Core 查询以过滤多个表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48968105/