EF核心多个实体具有共同类型的属性

时间:2019-05-29 11:32:02

标签: c# entity-framework-core

我具有以下架构(缩写为相关代码)

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无法做到这一点,那么有没有办法我可以自己编写可以满足我需要的扩展?

1 个答案:

答案 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;}
}

哪个版本最适合您,取决于您和您的特定业务需求。