是否可以在不使用中间 类 的情况下访问 EF Core 中的共享 TPH 列?
Is it possible to access a shared TPH column in EF Core without using intermediate classes?
在 EF Core TPH 设置中使用 shared columns 时,是否可以在投影期间访问共享列?
class Program
{
public static readonly ILoggerFactory MyLoggerFactory
= LoggerFactory.Create(builder => {
builder.AddConsole();
});
static async Task Main(string[] args)
{
using (var context = new ClientContext())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var actions = await context.Actions
.Select(a => new
{
Id = a.Id,
// this works - but really messy and complex in real world code
Message = (a as ActionA).Message ?? (a as ActionB).Message,
// this throws "Either the query source is not an entity type, or the specified property does not exist on the entity type."
// is there any other way to access the shared column Message?
// Message = EF.Property<string>(a, "Message"),
})
.ToListAsync();
actions.ForEach(a => Console.WriteLine(a.Id + a.Message));
}
}
public class ActionBase
{
public int Id { get; set; }
// ... other shared properties
}
public class ActionA : ActionBase
{
// shared with B
[Required]
[Column("Message")]
public string Message { get; set; }
// ... other specific properties
}
public class ActionB : ActionBase
{
// shared with A
[Required]
[Column("Message")]
public string Message { get; set; }
// ... other specific properties
}
public class ActionC : ActionBase
{
public string SomethingElse { get; set; }
// ... other specific properties
}
class ClientContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// TO USE SQL
//optionsBuilder
// .UseLoggerFactory(MyLoggerFactory)
// .UseSqlServer("Server=(localdb)\mssqllocaldb;Database=TPHSharedColumn;Trusted_Connection=True;MultipleActiveResultSets=true;Connect Timeout=30")
// .EnableSensitiveDataLogging(false);
// TO USE INMEMORY
optionsBuilder
.UseLoggerFactory(MyLoggerFactory)
.UseInMemoryDatabase(Guid.NewGuid().ToString());
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<ActionA>().HasData(new ActionA()
{
Id = 1,
Message = "A"
});
builder.Entity<ActionB>().HasData(new ActionB()
{
Id = 2,
Message = "B"
});
builder.Entity<ActionC>().HasData(new ActionC()
{
Id = 3,
SomethingElse = "C"
});
}
public DbSet<ActionBase> Actions { get; set; }
}
}
在这个简单的示例中,当然可以将 Message
移动到基数 class - 但是这可能会不小心添加 ActionC
和 Message
因为我需要删除 Required
属性。
我也知道我可以添加一个 ActionWithRequiredMessage
中间体 class 来继承 ActionA
和 ActionB
,但同样 - 在更复杂的现实世界示例中这是不可行的,因为还有其他共享列,并且 C# 不允许从多个 classes 继承 - EF Core 似乎不喜欢为此使用接口。
我只是想找到一种方法来直接访问共享列 - 并在投影中使用它。
有人知道这是否可行吗?
我找不到它的文档,但在 EF Core 5.x 中,您可以使用具有 [=19= 的派生实体的 any 访问共享列] 映射到它,例如所有这些工作
Message = (a as ActionA).Message,
Message = (a as ActionB).Message,
Message = ((ActionA)a).Message,
Message = ((ActionB)a).Message,
在 EF Core TPH 设置中使用 shared columns 时,是否可以在投影期间访问共享列?
class Program
{
public static readonly ILoggerFactory MyLoggerFactory
= LoggerFactory.Create(builder => {
builder.AddConsole();
});
static async Task Main(string[] args)
{
using (var context = new ClientContext())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var actions = await context.Actions
.Select(a => new
{
Id = a.Id,
// this works - but really messy and complex in real world code
Message = (a as ActionA).Message ?? (a as ActionB).Message,
// this throws "Either the query source is not an entity type, or the specified property does not exist on the entity type."
// is there any other way to access the shared column Message?
// Message = EF.Property<string>(a, "Message"),
})
.ToListAsync();
actions.ForEach(a => Console.WriteLine(a.Id + a.Message));
}
}
public class ActionBase
{
public int Id { get; set; }
// ... other shared properties
}
public class ActionA : ActionBase
{
// shared with B
[Required]
[Column("Message")]
public string Message { get; set; }
// ... other specific properties
}
public class ActionB : ActionBase
{
// shared with A
[Required]
[Column("Message")]
public string Message { get; set; }
// ... other specific properties
}
public class ActionC : ActionBase
{
public string SomethingElse { get; set; }
// ... other specific properties
}
class ClientContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// TO USE SQL
//optionsBuilder
// .UseLoggerFactory(MyLoggerFactory)
// .UseSqlServer("Server=(localdb)\mssqllocaldb;Database=TPHSharedColumn;Trusted_Connection=True;MultipleActiveResultSets=true;Connect Timeout=30")
// .EnableSensitiveDataLogging(false);
// TO USE INMEMORY
optionsBuilder
.UseLoggerFactory(MyLoggerFactory)
.UseInMemoryDatabase(Guid.NewGuid().ToString());
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<ActionA>().HasData(new ActionA()
{
Id = 1,
Message = "A"
});
builder.Entity<ActionB>().HasData(new ActionB()
{
Id = 2,
Message = "B"
});
builder.Entity<ActionC>().HasData(new ActionC()
{
Id = 3,
SomethingElse = "C"
});
}
public DbSet<ActionBase> Actions { get; set; }
}
}
在这个简单的示例中,当然可以将 Message
移动到基数 class - 但是这可能会不小心添加 ActionC
和 Message
因为我需要删除 Required
属性。
我也知道我可以添加一个 ActionWithRequiredMessage
中间体 class 来继承 ActionA
和 ActionB
,但同样 - 在更复杂的现实世界示例中这是不可行的,因为还有其他共享列,并且 C# 不允许从多个 classes 继承 - EF Core 似乎不喜欢为此使用接口。
我只是想找到一种方法来直接访问共享列 - 并在投影中使用它。
有人知道这是否可行吗?
我找不到它的文档,但在 EF Core 5.x 中,您可以使用具有 [=19= 的派生实体的 any 访问共享列] 映射到它,例如所有这些工作
Message = (a as ActionA).Message,
Message = (a as ActionB).Message,
Message = ((ActionA)a).Message,
Message = ((ActionB)a).Message,