2012-03-12 2 views
1

Пожалуйста, обратите внимание на следующий код:EF код первого - наследование и отношения

public class SomeEntity 
{ 
    public int Id { get; set; } 

    public int UserId { get; set; } 
    public virtual User User { get; set; } 
} 

public class SomeEntityA : SomeEntity 
{ 
    public int Number { get; set; } 
} 

public class SomeEntityB : SomeEntity 
{ 
    public string Text { get; set; } 
} 

public class User 
{ 
    public int Id { get; set; } 
    public int Username { get; set; } 

    public virtual ICollection<SomeEntityA> SomeEntitiesA { get; set; } 
    public virtual ICollection<SomeEntityB> SomeEntitiesB { get; set; } 
} 

Мой вопрос - есть ли способ, чтобы установить FluentApi сделать отношения, указанные выше работы должным образом? В настоящее время, когда к пользователю добавляется новый объект SomeEntityA, EF создает новую запись в таблице SomeEntities с правильно установленным User_Id FK, однако в SomeEntitesA, который является наследуемой таблицей, есть также свойство FK User_Id - установлено как null, и когда я пытаюсь получить SomeEntitesA коллекция из объекта User - она ​​пуста. Я действительно понимаю, почему это происходит, но я не уверен, есть ли способ исправить это? Единственное решение, которое приходит на ум в этот момент заменить следующий код:

public virtual ICollection<SomeEntityA> SomeEntitiesA { get; set; } 
    public virtual ICollection<SomeEntityB> SomeEntitiesB { get; set; } 

с:

public virtual ICollection<SomeEntity> SomeEntitiesA { get; set; } 
    public virtual ICollection<SomeEntity> SomeEntitiesB { get; set; } 

и настроить FluentApi.

Любые мысли будут высоко оценены.

ответ

1

Посмотрите на этот вопрос/ответ, классы имеют точно такую ​​же структуру, как и ваша, и есть подробное объяснение, почему-то не работает, как ожидалось:

Is inheritance of navigation properties supported?

Как Slauma отметил, есть довольно простое решение, чтобы обойти эту проблему, выполнив следующие действия (скопированный из связанного ответа и подходит к вашему примеру):

public class User 
{ 
    public int Id { get; set; } 
    public int Username { get; set; } 

    // this is necessary to have access to the related SomeEntityAs/SomeEntityBs 
    // also it cant be private otherwise EF will not overload it properly 
    public virtual ICollection<SomeEntity> SomeEntities { get; set; } 

    public IEnumerable<SomeEntityA> SomeEntitiesA { get { return this.SomeEntities.OfType<SomeEntityA>(); } } 
    public IEnumerable<SomeEntityB> SomeEntitiesB { get { return this.SomeEntities.OfType<SomeEntityA>(); } } 
} 
+0

BTW: вы можете принести решение (последний фрагмент кода) из вашего другого ответа на вопрос здесь. Потому что это реальная альтернатива. Он всегда будет загружать все базовые объекты, хотя и «OfType» затем отфильтровывается в памяти, поэтому есть потенциальная нагрузка на данные. Но с другой стороны, у вас есть «Пользователь» в базовом классе, а не «дублируется» в производных классах, как в моем решении. Во что бы то ни стало интересное решение и стоит рассмотреть! (Я буду повышать :)) – Slauma

+0

thx для подсказки, только что обновил ответ. – ntziolis

+0

Спасибо, я думаю, что я буду придерживаться такого подхода, но я хотел бы узнать больше о его производительности? Даже если я изменяю IEnumerable на тип IQueryable и, например, использовать метод Take(), он все равно будет сначала загружать все эти сущности в память? –

1

Ваше предложенное решение также не будет работать, потому что вы не можете связывать два навигационных свойства User.SomeEntitiesA и User.SomeEntitiesB с той же конечной точкой SomeEntity.User. Вы на самом деле нужно было бы двух пользователей:

public class SomeEntity 
{ 
    public int Id { get; set; } 

    public int UserAId { get; set; } 
    [InverseProperty("SomeEntitiesA")] 
    public virtual User UserA { get; set; } 

    public int UserBId { get; set; } 
    [InverseProperty("SomeEntitiesB")] 
    public virtual User UserB { get; set; } 
} 

Но тогда вы можете также сохранить типы коллекций, как они есть, и переместить пользователей к производным лиц:

public class SomeEntity 
{ 
    public int Id { get; set; } 
} 

public class SomeEntityA : SomeEntity 
{ 
    public int Number { get; set; } 

    public int UserId { get; set; } 
    public virtual User User { get; set; } 
} 

public class SomeEntityB : SomeEntity 
{ 
    public string Text { get; set; } 

    public int UserId { get; set; } 
    public virtual User User { get; set; } 
} 

public class User 
{ 
    public int Id { get; set; } 
    public int Username { get; set; } 

    public virtual ICollection<SomeEntityA> SomeEntitiesA { get; set; } 
    public virtual ICollection<SomeEntityB> SomeEntitiesB { get; set; } 
} 

Вам не нужно указывать [InverseProperty] в этом случае, поскольку соглашения будут теперь определять правильные пары свойств навигации.

+0

Спасибо за ответ, но основная идея заключается в том, чтобы держать пользователя в базе класс, поэтому, когда я создаю a View, чтобы показать эти сущности, я могу отображать имя пользователя, а также независимо от класса типа A или B. –

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