我是实体框架的新手,当我的模型看起来像这样时,我很难弄清楚如何用连接查询(大大简化)
class Customer
{
public int Id {get; set;}
public Vehicles Vehicles {get; set;}
}
class Vehicles
{
public List<Vehicle> Items {get; set;}
}
class Vehicle
{
public int Id {get; set;}
public int CustomerId {get; set;}
}
如果我直接将List<Vehicle>
放在客户类上。我可以像这样做流畅的映射
builder.Entity<Customer>()
.HasMany(x => x.Items)
.WithOne()
.HasForeignKey(x => x.CustomerId);
然后,我可以做到这一点,然后我用车辆取回客户对象
db.Customers.Include(x => x.Items).FirstOrDefault(x => x.Id == 1);
我不理解的是如何使用我原来的模型进行此操作。如果可能的话,我想让他们保持原样。我已经尝试在我的onModelCreating
方法中做了各种版本的这个没有运气。
builder.Entity<Customer>(t =>
{
t.OwnsOne(x => x.Vehicles, v =>
{
v.HasMany(x => x.Items).WithOne().HasForeignKey(x => x.CustomerId);
});
});
可以映射原始类,但是以非常违反直觉的方式。
由于Vehicles
类只是一个容器,因此将其作为所拥有的实体进行映射似乎是最自然的方式。但是,目前EF Core不允许拥有实体处于关系的主要方面,在您的情况下,这是必需的。
因此,您需要将Vehicles
类映射为与Customer
共享相同表的常规“实体” - 即所谓的table splitting。你必须明确表示EF Core对所拥有的实体隐式执行的所有操作 - 定义shadow property和map是与Customer
一对一关系的PK和FK。您还需要明确地将Vehicle.CustomerId
映射为FK,因为从EF的角度来看,Vehicle
与Vehicles
而不是Custome
相关,因此假定的传统FK属性/列名称将为VehiclesId
。请注意,使用此模型,您将永远无法定义Customer
的反向导航属性Vehicle
。
话虽如此,这里需要流畅的配置:
modelBuilder.Entity<Vehicles>(builder =>
{
// Table
builder.ToTable(modelBuilder.Entity<Customer>().Metadata.Relational().TableName);
// PK
builder.Property<int>("Id");
builder.HasKey("Id");
// One-to-one relationship with Customer
builder.HasOne<Customer>()
.WithOne(e => e.Vehicles)
.HasForeignKey<Vehicles>("Id");
// One-to-many relationship with Vehicle
builder.HasMany(e => e.Items)
.WithOne()
.HasForeignKey(e => e.CustomerId);
});
和用法:
db.Customers
.Include(x => x.Vehicles.Items) // <--
// ...