EF Linq to 实体查询为 TPC CTP5 代码优先实体生成 UNION
我有以下实体:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
public class HappyUser : User
{
public bool IsHappy { get; set; }
}
我正在使用每个具体类型表 (TPC) 配置实体,以便生成用户表和 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;
Users 的 SQL 生成 UNION。这不是我所期望或想要的。我想简单地从用户表中检索行。
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 的缺陷?
I have the following entities:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
public class HappyUser : User
{
public bool IsHappy { get; set; }
}
I am configuring the entities using Table Per Concrete Type (TPC) in order to generate a User table and a HappyUser table. I want the HappyUser table to include the properties of the User class, and I don't want any relationship between the two tables.
I configure the entities as follows:
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");
});
}
}
The tables are generated correctly, but when I query the tables, EF generates a UNION on the User and HappyUser table. The query is as follows:
UserTest db = new UserTest();
var users = from u in db.Users
select u;
var happyUsers = from u in db.Users.OfType<HappyUser>()
select u;
The SQL for the Users generates a UNION. This is not what I expect or want. I'd like to simply retrieve the rows from the Users table.
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]
The SQL for the HappyUsers works as expected.
SELECT
'0X0X' AS [C1],
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[IsHappy] AS [IsHappy]
FROM [dbo].[HappyUser] AS [Extent1]
Any ideas what I am doing wrong? Or is this a defect in EF?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
HappyUsers是用户。因此,
db.Users
应该返回两者。 EF 在这里是正确的。但是,EF 确实有一个限制:(无论如何,在 L2E 中)无法返回仅一种类型的结果。由于里氏替换原则,您通常不想这样做。但如果您这样做,您可以在 ESQL 中完成此操作,并且有(有些乏味的)L2E 解决方法。
底线:如果您发现自己想这样做,请重新考虑您的设计。在这种情况下,继承可能不是正确的关系。
HappyUsers are Users. Hence,
db.Users
should return both. The EF is correct, here.However, the EF does have a limitation: There is no way to (in L2E, anyway) return results of only one type. Due to the Liskov Substitution Principal, you don't generally want to do this. But if you do, you can do it in ESQL, and there are (somewhat tedious) workarounds for L2E.
Bottom line: If you find yourself wanting to do this, rethink your design. Inheritance is probably not the right relationship in this case.
@Craig Stuntz 是对的,因为两种类型都是相关的,EF 将保持这种关系完整。
如果您想解耦两种 User 类型,那么您可以使用抽象基类。
EF 现在会将这两个实体视为单独的实体,无需再调用
MapInheritedProperties()
。您的选择语句将如下所示:
@Craig Stuntz is right, since both types are related, EF will keep that relation intact.
If you want to decouple both User types, then you could use an abstract base class.
EF will now treat both entities as seperate and there's no need to call
MapInheritedProperties()
anymore.Your select statements would then look like: