由于EFCore要求您显式创建连接实体,我试图找到使这些代码更易于管理的方法。我正在学习本教程(4部分系列,本部分和下一部分是相关部分):https://blog.oneunicorn.com/2017/09/25/many-to-many-relationships-in-ef-core-2-0-part-2-hiding-as-ienumerable/
它将联接类隐藏为私有ICollection
,然后使用已连接的entitis填充另一个ICollection,因此它以与EF6类似的方式工作。以下是我跟踪人们拥有的汽车的实施方式:
public class Person
{
public Person() =>
Cars = new JoinCollectionFacade<Car, PersonCar>
(PersonCars, pc => pc.Car, c => new PersonCar { Person = this, Car = c });
public int Id { get; set; }
public string Name { get; set; }
private ICollection<PersonCar> PersonCars { get; } = new List<PersonCar>();
[NotMapped]
public ICollection<Car> Cars { get; }
}
public class Car
{
public Car() => Persons = new JoinCollectionFacade<Person, PersonCar>
(PersonCars, pc => pc.Person, p => new PersonCar { Person = p, Car = this });
public int Id { get; set; }
public string Manufacturer { get; set; }
private ICollection<PersonCar> PersonCars { get; } = new List<PersonCar>();
[NotMapped]
public ICollection<Person> Persons { get; }
}
public class PersonCar
{
public Person Person { get; set; }
public int PersonId { get; set; }
public Car Car { get; set; }
public int CarId { get; set; }
}
我的映射:
modelBuilder.Entity<PersonCar>(e =>
{
e.HasKey(t => new { t.PersonId, t.CarId });
e.HasOne(pc => pc.Person).WithMany("PersonCars");
e.HasOne(pc => pc.Car).WithMany("PersonCars");
});
一些种子数据:
using (var db = new ManyDbContext())
{
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
db.Persons.AddRange(
new Person() { Name = "John" },
new Person() { Name = "Peter" },
new Person() { Name = "Paul" }
);
db.Cars.AddRange(
new Car() { Manufacturer = "Audi" },
new Car() { Manufacturer = "Honda" },
new Car() { Manufacturer = "Mercedes" },
new Car() { Manufacturer = "Ferrai" },
new Car() { Manufacturer = "Porche" }
);
db.SaveChanges();
db.PersonCars.AddRange(
new PersonCar() { PersonId = 1, CarId = 2},
new PersonCar() { PersonId = 1, CarId = 3 },
new PersonCar() { PersonId = 2, CarId = 2 },
new PersonCar() { PersonId = 3, CarId = 1 }
);
db.SaveChanges();
}
如果我撤回包括下面的汽车在内的人员列表,它可以正常工作并输出数据:
var drivers = db.Persons.Include("PersonCars.Car").ToList();
foreach(var person in drivers)
{
foreach(var car in person.Cars)
{
Console.WriteLine($"{person.Name} has a {car.Manufacturer}");
}
}
但是,如果我尝试在调试器中查看Cars
集合结果,那么VS2017崩溃哪个不好但在代码级别它似乎有效。
但是,让我说我想过滤列表只是奥迪司机,下面的结果为0结果:
var audiDrivers = db.Persons.Include("PersonCars.Car").Where(x => x.Cars.Any(c => c.Manufacturer == "Audi"));
该系列文章主要关注改进添加/删除,而不提及过滤。我希望使用该功能,但我希望能够按Persons
过滤Cars
。
如果我将PersonCars
收藏公开,那么我可以这样做:
var audiDrivers = db.Persons
.Include(i => i.PersonCars).ThenInclude(i => i.Car)
.Where(x => x.PersonCars.Select(pc => pc.Car).Any(c => c.Manufacturer == "Audi"))
.ToList();
总结一下:
如果导航属性像文章建议的那样是私有的,可以过滤查找吗?
为什么VS2017在查看Car
集合时会崩溃?
有没有比EF6更简单的方法呢?
答案 0 :(得分:1)
我个人会直接与联接实体合作。它可能不是“漂亮”,但它是最直接的方法。最终,开发和维护代码将更容易,更快捷。事实上,你在开发过程中尽早使用替代方法解决了这些基本问题,我认为可以证明这一点。
我的建议是:使用EF Core,而不是反对它。它不像EF6那样成熟,但它最终会到达那里。