我具有以下架构(缩写为相关代码)
class Person
{
public int Id {get;set;}
public string Name {get;set;}
public ICollection<MetaData> MetaData {get;set;}
}
class Car
{
public int Id {get;set;}
public string Make {get;set;}
public ICollection<MetaData> MetaData {get;set;}
}
class Building
{
public int Id {get;set;}
public string Address {get;set;}
public ICollection<MetaData> MetaData {get;set;}
}
class MetaData
{
public int Id {get;set;}
public string CLRType {get;set;}
public string Value {get;set;}
// These two fields together form a connection to the other entities
public int Key {get;set;} // the PK of the connected entity
public string Type {get;set;} // nameof(Entity)
}
如何在EF Core中表示呢?
使用OwnsMany
为每个类型+元数据类型连接创建一个表
如果我尝试使用TPH,则元数据表会以每个连接的实体的其他字段结尾
这些解决方案都不适合我。 我不需要数据库中的约束,我只想一种表达这种关系的方式,以使EF Core能够充实我的模型 即使我必须手动提供sql(即使对于读写也是如此)
如果提供的现有API无法做到这一点,那么有没有办法我可以自己编写可以满足我需要的扩展?
答案 0 :(得分:1)
您正在混合两种关系。 您既可以具有类型安全的关系,又可以在Metadata类上复制外键(别忘了添加唯一的约束)
class MetaData
{
public int Id {get;set;}
public string CLRType {get;set;}
public string Value {get;set;}
public int PersonId {get;set;}
public Person Person {get;set;}
public int CarId {get;set;}
public Car Car {get;set;}
public int BuildingId {get;set;}
public Person Building {get;set;}
}
或者保持松散耦合,然后手动进行连接
class Car
{
public int Id {get;set;}
public string Make {get;set;}
}
// not mapped in the database, just used for display purposes
class CarViewModel
{
public int Id {get;set;}
public string Make {get;set;}
}
var carIds = new [] { 1, 2, 3 };
// we use 2 contexts here so we can query both tables at the same time.
// otherwise Task.WhenAll(...) would throw an exception.
// you should also disable change tracking to improve speed.
var carsTask = context1.Cars
.Where(c => carIds.Contains(c.Id))
.ToListAsync();
var metadataTask = context2.Metadata
.Where(m => carIds.Contains(m.Key) && m.Type == "Car")
.GroupBy(m => m.Key)
.ToDictionaryAsync(g => g.Key, g => g.ToList());
await Task.WhenAll(carsTask, metadataTask).ConfigureAwait(false);
var cars = carsTask.Result
.Select(c => new CarViewModel
{
Id = c.Id,
Make = c.Make,
Metadata = metadataTask.Result.TryGetValue(c.Id, out var m) ? m : Array.Empty<Metadata>(),
})
.ToList();
或者有单独的元数据表
abstract class MetaData
{
public int Id {get;set;}
public string CLRType {get;set;}
public string Value {get;set;}
}
class CarMetaData : MetaData
{
public int CarId {get;set;}
public Car Car {get;set;}
}
class Car
{
public int Id {get;set;}
public string Make {get;set;}
public ICollection<CarMetaData> MetaData {get;set;}
}
哪个版本最适合您,取决于您和您的特定业务需求。