我有以下实体:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
public class HappyUser : User
{
public bool IsHappy { get; set; }
}
我正在使用Table Per Concrete Type(TPC)配置实体,以生成User表和HappyUser表。我希望HappyUser表包含User类的属性,我不希望这两个表之间有任何关系。
我按如下方式配置实体:
public class UserTest : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<HappyUser> HappyUsers { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<HappyUser>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("HappyUser");
});
}
}
表是正确生成的,但是当我查询表时,EF会在User和HappyUser表上生成UNION。查询如下:
UserTest db = new UserTest();
var users = from u in db.Users
select u;
var happyUsers = from u in db.Users.OfType<HappyUser>()
select u;
用户的SQL生成UNION。这不是我期望或想要的。我想简单地从Users表中检索行。
SELECT
CASE WHEN ([UnionAll1].[C2] = 1) THEN '0X' ELSE '0X0X' END AS [C1],
[UnionAll1].[Id] AS [C2],
[UnionAll1].[Name] AS [C3],
CASE WHEN ([UnionAll1].[C2] = 1) THEN CAST(NULL AS bit) ELSE [UnionAll1].[C1] END AS [C4]
FROM (SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
CAST(NULL AS bit) AS [C1],
cast(1 as bit) AS [C2]
FROM [dbo].[User] AS [Extent1]
UNION ALL
SELECT
[Extent2].[Id] AS [Id],
[Extent2].[Name] AS [Name],
[Extent2].[IsHappy] AS [IsHappy],
cast(0 as bit) AS [C1]
FROM [dbo].[HappyUser] AS [Extent2]) AS [UnionAll1]
HappyUsers的SQL按预期工作。
SELECT
'0X0X' AS [C1],
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[IsHappy] AS [IsHappy]
FROM [dbo].[HappyUser] AS [Extent1]
任何想法我做错了什么?或者这是EF的缺陷?
答案 0 :(得分:1)
HappyUsers 是用户。因此,db.Users
应返回两者。 EF在这里是正确的。
然而,EF确实有一个限制:无法(在L2E中,无论如何)返回仅一种类型的结果。由于Liskov Substitution Principal,您通常不想这样做。但如果你这样做,you can do it in ESQL, and there are (somewhat tedious) workarounds for L2E。
结论:如果您发现自己想要这样做,请重新考虑您的设计。在这种情况下,继承可能不是正确的关系。
答案 1 :(得分:1)
@Craig Stuntz是对的,因为两种类型都是相关的,EF将保持这种关系不变。
如果要解耦两种用户类型,则可以使用抽象基类。
public abstract class AbstractUser
{
public int Id { get; set; }
public string Name { get; set; }
}
public class User : AbstractUser
{
}
public class HappyUser : AbstractUser
{
public bool IsHappy { get; set; }
}
EF现在将两个实体分开处理,不再需要调用MapInheritedProperties()
。
您的选择语句将如下所示:
var users = db.Users.Where(...);
var happyUsers = db.HappyUsers.Where(...);