EF Linq к объектам, генерирующим запрос UNION для объекта с кодом TPC CTP5 - PullRequest
4 голосов
/ 27 января 2011

У меня есть следующие сущности:

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

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

Я настраиваю сущности, используя таблицу для конкретного типа (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 генерирует UNION для таблиц User и HappyUser.Запрос выглядит следующим образом:

        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]

SQL для HappyUsers работает как положено.

SELECT 
'0X0X' AS [C1], 
[Extent1].[Id] AS [Id], 
[Extent1].[Name] AS [Name], 
[Extent1].[IsHappy] AS [IsHappy]
FROM [dbo].[HappyUser] AS [Extent1]

Есть идеи, что я делаю не так?Или это дефект в EF?

Ответы [ 2 ]

1 голос
/ 28 января 2011

@ Крейг Штунц прав, так как оба типа связаны, EF сохранит это отношение без изменений.

Если вы хотите разделить оба типа User, то вы можете использовать абстрактный базовый класс.

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(...);
1 голос
/ 27 января 2011

HappyUsers являются пользователями. Следовательно, db.Users должен вернуть оба. EF правильно, здесь.

Однако EF имеет ограничение: в любом случае, в L2E нет способа вернуть результаты только одного типа. Из-за принципа замены Лискова вы обычно не хотите этого делать. Но если вы это сделаете, вы можете сделать это в ESQL, и для L2E .

есть (несколько утомительные) обходные пути

Итог: если вы захотите это сделать, переосмыслите свой дизайн. Наследование, вероятно, не правильные отношения в этом случае.

...