4

次のエンティティがあります。

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class HappyUser : User
{
    public bool IsHappy { get; set; }
}

User テーブルと HappyUser テーブルを生成するために、Table Per Concrete Type (TPC) を使用してエンティティを構成しています。HappyUser テーブルに User クラスのプロパティを含めたいのですが、2 つのテーブル間の関係は望んでいません。

エンティティを次のように構成します。

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 の欠陥ですか?

4

2 に答える 2

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()

select ステートメントは次のようになります。

var users = db.Users.Where(...);
var happyUsers = db.HappyUsers.Where(...);
于 2011-01-27T21:49:46.527 に答える
1

HappyUsersユーザーです。したがって、両方db.Users 返す必要があります。ここでは、EF は正しいです。

ただし、EF には制限があります。(L2E ではとにかく) 1 つのタイプのみの結果を返す方法はありません。Liskov Substitution Principal により、通常はこれを行いたくありません。しかし、もしそうなら、ESQL でそれを行うことができ、L2E には (やや面倒な) 回避策があります。

結論: これをやりたいと思ったら、デザインを考え直してください。この場合、継承はおそらく適切な関係ではありません。

于 2011-01-27T20:44:13.970 に答える