Reputation: 1819
More than one year later from my first question on SO (Filter base entity from child entities' properties), I have a similar problem.
I have an abstract base type
public abstract class Base{
}
I have some child entities that inherits from this Base Type
public class Child1 : Base{
public virtual NavigationProperty NavigationProperty {get; set; }
public int NavigationPropertyId {get; set}
}
public class Child2 : Base{
public virtual NavigationProperty NavigationProperty {get; set; }
}
The child entities all have NavigationProperty property. And the NavigationProperty class is like
public class NavigationProperty{
public virtual ICollection<Child1> Child1s {get; set;}
public virtual Child2 Child2s {get; set;}
}
There one-to-one mapping between Child2 and NavigationProperty; one-to-many relationship between Child1 and NavigationProperty. In order to these mapping to work i am using TPT. My first question is, can I move
public NavigationProperty NavigationProperty {get; set; }
to Base class?
I am trying this for a whole day and did not have any success. If it is not possible can i at least access the NavigationProperty from the base type. After all the childs have this property, I tried something like
public abstract class Base{
public abstract NavigationProperty NavigationProperty {get; set; }
}
....
public abstract class Child2{
public override NavigationProperty NavigationProperty {get; set; }
}
But entity framework gives the following error.
Sequence contains more than one matching element
I can use something like
public abstract class Base{
public abstract NavigationProperty GetNavigationProperty();
}
public abstract class Child2{
public override NavigationProperty NavigationProperty {get; set; }
public override NavigationProperty GetNavigationProperty(){
return NavigationProperty;
}
}
But I do not want to introduce these extra methods. Are they any way to achieve this more elegantly?
Edit:
I forgot to mention that I have already tried putting [NotMapped]
attribute. I guess EF [NotMapped]
attribute is inherited too so the child properties are not mapped too.
I do not expect to Linq-to-Entites to work. I do not want to be able to query base entities with navigation properties. I simply want to get rid of GetNavigationProperty and SetNavigationProperty methods. So when i try to access NavigationProperty from base class it should be loaded into memory, that's all. However, after a week of effort, I do not think it is possible.
Upvotes: 4
Views: 1534
Reputation: 4971
EDIT x1 Updated code to avoid literal strings for property name
A little bit of reflection seems to do the job. Class setup;
public class NavigationProperty
{
public NavigationProperty(string name)
{
Name = name;
}
public string Name { get; set; }
}
public abstract class Base
{
public NavigationProperty NavigationProperty
{
get
{
string propertyName = MethodBase.GetCurrentMethod().Name.Replace("get_", string.Empty);
PropertyInfo property = this.GetType().GetProperty(propertyName);
if (property != null)
{
nav = (NavigationProperty)property.GetValue(this, new object[] { });
}
return nav;
}
set
{
string propertyName = MethodBase.GetCurrentMethod().Name.Replace("set_", string.Empty);
PropertyInfo property = this.GetType().GetProperty(propertyName);
if (property != null)
{
property.SetValue(this, value, new object[] { });
}
}
}
}
public class Child1 : Base {
public NavigationProperty NavigationProperty { get; set; }
public int NavigationPropertyId { get; set; }
}
public class Child2 : Base{
public NavigationProperty NavigationProperty { get; set; }
}
And in your code;
Child1 c1 = new Child1() { NavigationProperty = new NavigationProperty("child1Value") };
Child2 c2 = new Child2() { NavigationProperty = new NavigationProperty("child2Value") };
Base somebase = c1;
NavigationProperty childNav = somebase.NavigationProperty;
// childNav.Name now contains "child1Value"
Does this meet your requirements? It's a little more clunky than using an abstract
method but it at least means you don't have to refactor every child class
Upvotes: 1
Reputation:
Short of finding support in Entity Framework for your scenario, you could try this:
public interface IHasNavigationProperty {
NavigationProperty NavigationProperty { get; }
}
public class Child1 : Base, IHasNavigationProperty {
public NavigationProperty NavigationProperty { get; set; }
}
public class Base {
public void AMethodThatDoesStuff() {
if (this is IHasNavigationProperty) {
var navigationProperty = ((IHasNavigationProperty)this).NavigationProperty;
/* do stuff with NavigationProperty */
}
}
}
Upvotes: 1
Reputation: 177153
Can I move
public NavigationProperty NavigationProperty {get; set; }
to Base class?
No, because the inverse properties in entity NavigationProperty
refer to Child1
and Child2
, not to Base
. Navigation properties always must be properties of the declared type and cannot be moved to a base type in the inheritance chain.
For the second problem you could try to exclude the abstract navigation property from the mapping:
public abstract class Base {
[NotMapped]
public abstract NavigationProperty NavigationProperty {get; set; }
}
(or modelBuilder.Entity<Base>().Ignore(b => b.NavigationProperty);
with Fluent API).
You won't be able though to use Base.NavigationProperty
in any queries because you can't use not mapped properties with LINQ-to-Entities.
Upvotes: 1