将ASP Core 2与EF Core和SQL Server一起使用。我有,我认为这是一个直接的任务,检索给定分销商的制造商(或个别制造商)名单。
Users表提供经过身份验证的用户,每个用户都与一个分发服务器相关联(并在模型中表示为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()
如果与经过身份验证的分销商相关联,则应返回单个制造商。
要做到这一点,我尝试各种配方,如:
ICollection<DistributorManufacturers>
VS抱怨DistributorId
不包含.ThenInclude
的定义(即使我从课程中复制/粘贴了它)。它在概念上与我在地址上的过滤器不同。
我还尝试title='WordPress Gallery'><div style='display:block;width:180px;height:20px;text-align:center;border-radius:3px;-moz-border-radius:3px
添加Distributors表但没有运气。
DistributorManufacturers表是使用Scaffold-DbContext创建的,并且定义了外键和导航属性。
答案 0 :(得分:1)
所以,做了一些工作来重新创建你的模型。我唯一改变的是我在Distributor表中添加了userId
而不是相反。这将是一个很长的答案..所以挂在
模型(省略了用户和地址实体,因为它们并没有什么特别之处)
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()
操作中,您想要为登录的Manufacturers
,AKA Distributor
返回所有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)
正常工作,只需将制造商ID添加到where
子句即可。由于它在DistributorManufacturer
上进行内部联接,如果与登录用户没有任何关系,它将返回null。
注意:在EF Core中,当您拥有多对多关系时,您需要(至少现在......)将联合表作为实体。您可以在此处查看有关此问题的讨论:https://github.com/aspnet/EntityFrameworkCore/issues/1368
答案 1 :(得分:0)
在我看来,您希望在分销商和制造商之间配置多对多关系:每个分销商都有零个或多个制造商,每个制造商都会向零个或多个分销商提供。
如果您根据the entity framework code first many-to-many conventions,配置了这种多对多关系,您可能会遇到以下情况:
class Distributor
{
public int Id {get; set;}
public string Name {get; set;}
// a distributor has exactly one Address using foreign key:
public int AddressId {get; set;}
public Address Address {get; set;}
// a Distributor has zero or more Manufacturers: (many-to-many)
public virtual ICollection<Manufacturer> Manufacturers {get; set;}
// a Distirbutor has zero or more Users: (one-to-many)
public virtual ICollection<User> Users {get; set;}
}
class Manufacturer
{
public int Id {get; set;}
public string Name {get; set;}
// a Manufacturer has exactly one Address using foreign key:
public int AddressId {get; set;}
public Address Address {get; set;}
// a Manufacturer has zero or more Distributors (many-to-many)
public virtual ICollection<Distributor> Distributors {get; set;}
}
还有一个用户:每个用户都属于一个经销商
class User
{
public int Id {get; set;}
// a user belongs to exactly one Distributor, using foreign key:
public int DistributorId {get; set;}
public virtual Distributor Distributor {get; set;}
...
}
最后是DbContext
class MyDbContext : DbContext
{
public DbSet<Distributor> Distributors {get; set;}
public DbSet<Manufacturer> Manufacturers {get; set;}
public DbSet<User> Users {get; set;}
public DbSet<Address> Addresses {get; set;}
}
以上是实体框架需要了解的所有内容,以了解您希望分销商和ManuFacturers之间的多对多。实体框架将为您创建一个合适的联结表,尽管您在查询中不会需要它,我将在下面向您展示。如果您不喜欢实体框架为您创建的默认联结表,则可以使用Fluent API来定义表名和列名:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Distributor>()
.HasMany(distributor=> distributor.Manufacturers)
.WithMany(manufacturer => manufacturer.Distributors)
.Map(map =>
{
map.MapLeftKey("DistributorId");
map.MapRightKey("ManufacturerId");
map.ToTable("DistributorsManufacturers");
});
虽然内部实体框架将使用联结表,但您不会在查询中使用它,只需使用ICollections:
我有一个_user,我想要零或一个的几个属性 该用户的分销商,以及所有的几个属性 本经销商的制造商
尽管可以使用Include语句,但这样做很少明智。数据库查询较慢的部分之一是将所选数据传输到您的进程,因此您应该将传输的数据量限制为您实际计划使用的属性。 Include将传输所有属性,我高度怀疑你是否会使用它们,尤其是所有具有相同值的外键。
所以你的查询使用ICollection:
var _user = ... // I've got a User
var result = dbContext.Distributers
.Where(distributor => distributor.Id == _user.DistributorId)
.Select(distributor => new
{
// select only the distributor properties you plan to use
Id = distributor.Id,
Name = distributor.Name,
Address = new
{
// again: only the properties you plan to use
Street = distributor.Address.Street,
City = distributor.Address.City,
Zip = distributor.Address.Zip,
}),
// fetch (all or some) manufacturers of this distributor
Manufacturers = distributor.Manufacturers
.Where(manufacturer => manufacturer.Address.NavigationState == "CA")
.Select(manufacturer => new
{
// select only the properties you plan to use
// probably not the foreign key to the junction table
Name = manufacturer .Name,
Address = new {...},
...
})
.ToList(),
})
.SingleOrDefault();
可能你想要一些不同的属性,但你得到了要点