2011-01-27 3 views
3

У меня есть следующие объекты:EF Linq для субъектов запроса, генерирующего UNION для TPC CTP5 кодовых первого лица

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

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

Я настраиваемая сущность, используя таблицу Per Бетонного типа (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 генерирует UNION на пользователя и 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?

+0

Я думаю, что в нижней строке, если я не могу изменить модель объекта или база данных, то EF не поддерживает этот сценарий. Итак, я изменю модель сущности, которая является меньшим количеством зла. Всем спасибо. –

+0

Чтобы быть понятным, это L2E, который не поддерживает это, а не EF. Как я уже сказал, вы можете сделать это на ESQL. –

ответ

0

Адрес: HappyUsers Пользователи. Следовательно, db.Usersдолжен вернуть оба. Здесь EF верен.

Однако у EF есть ограничение: нет способа (в L2E, в любом случае) возвращать результаты только один тип. Из-за Принципа заместителя Лискова вы вообще этого не хотите. Но если да, то you can do it in ESQL, and there are (somewhat tedious) workarounds for L2E.

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

+0

HappyUsers - это пользователи, основанные на иерархии классов, но я сопоставляю объекты для разделения таблиц. Я понял, что EF не будет устанавливать связь между этими двумя таблицами. –

+0

Я не могу настроить существующую модель сущности и/или таблицы базы данных. Моя цель - использовать EF для извлечения и сохранения данных. Есть ли альтернативная конфигурация, которая позволила бы двум таблицам не иметь никаких отношений? –

+0

Это не выводит связь между ** таблицами **, это выводит связь между ** типами **. И это правильно. Если вы не хотите наследования класса, то не просите об этом. В его нынешнем виде, когда вы запрашиваете все 'Пользователь', он предоставит вам все объекты, которые являются либо типом« Пользователь », либо имеют« Пользователь »в иерархии наследования. Это правильное поведение. Похоже, вы на самом деле не хотите, чтобы «HappyUser» наследовал от «User», что может быть хорошо для вашего домена. Но если вы не можете изменить модель, вы должны жить с ней - см. Ссылку в моем ответе. –

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

 Смежные вопросы

  • Нет связанных вопросов^_^