4

Closed

NotMapped on base property throws if derived type discovered first

description

An exception is thrown when the derived entity type is discovered before the base entity type containing an ignored property.

"You cannot use Ignore method on the property 'BaseProperty' on type 'DerivedEntity' because this type inherits from the type 'BaseEntity' where this property is mapped. To exclude this property from your model, use NotMappedAttribute or Ignore method on the base type."
var modelBuilder = new DbModelBuilder();
 modelBuilder.Entity<DerivedEntity>();
 modelBuilder.Entity<BaseEntity>();
 modelBuilder.Build(new DbProviderInfo("System.Data.SqlClient", "2008"));

public class BaseEntity
{
    public long Id { get; set; }
    [NotMapped]
    public string BaseProperty { get; set; }
}

public class DerivedEntity : BaseEntity
{
}

WORKAROUND

Here's the algorithm to fix your code if you get the exception "You cannot use Ignore method on the property 'PropertyX' on type 'TypeY' because this type inherits from the type 'TypeZ' where this property is mapped. To exclude this property from your model, use NotMappedAttribute or Ignore method on the base type.":
  1. Are you calling modelBuilder.Entity<TypeY>().Ignore(p => p.PropertyX);?
    Yes. Replace this call with modelBuilder.Entity<TypeZ>().Ignore(p => p.PropertyX);
    Goto 3.
    No. Goto 2.
  2. There should be a NotMapped attribute on property 'PropertyX' that's defined on 'TypeZ'. Is 'TypeZ' included in the model? (i.e. it's a valid entity type and it isn't ignored)
    Yes. Ensure that 'TypeZ' is discovered before 'TypeY', to do this put modelBuilder.Entity<TypeZ>(); before modelBuilder.Entity<TypeY>();
    Goto 3.
    No. Remove NotMapped attribute from property 'PropertyX'. For each 'TypeW' directly derived from 'Z' add modelBuilder.Entity<TypeW>().Ignore(p => p.PropertyX);
    Goto 3.
  3. Run your tests. Did you get another exception with the same text, but different types?
    Yes. Goto 1.
    No. Enjoy!
Closed Jan 21, 2014 at 6:05 PM by BriceLambson

comments

AndriySvyryd wrote Sep 11, 2012 at 10:38 PM

Confirmed as a bug.

realstrategos wrote Sep 19, 2012 at 2:19 PM

How is this a Low Impact? ... any non-simple implementation that uses base classes will not be able to upgrade from 4.3

wtlatli wrote Sep 25, 2012 at 10:36 AM

I upgraded from 4.3 to 5 and my solution can't compile because of this bug (using the nuget lastest release 5.0.0).
I can't see how this is Low Impact !

If any, please provide a workaround.

divega wrote Sep 25, 2012 at 7:36 PM

@wtlatli: could you provide a repro that shows what you are seeing? The bug described here shouldn't prevent you from compiling the application.

AndriySvyryd wrote Sep 28, 2012 at 9:28 PM

Updated the description with a minimal repro

wtlatli wrote Oct 1, 2012 at 7:18 AM

@divega : I solved my compilation issue that was due to a third party tool and not just EF. my solution was to replace the NotMapped attribute by .Ignore() in the code with fluent api.

AndriySvyryd wrote Oct 11, 2012 at 7:38 PM

Fixed in 25d5ead4ddb0545164a9ecab60959ea558a64a05

NeRane wrote Dec 27, 2012 at 2:03 PM

I do not see how this is LOW IMPACT at all.

NeRane wrote Dec 27, 2012 at 2:09 PM

Actually, I just found an easy way to get around this. Define the NotMapped in FluentAPI instead of Attributes.

ex:
        modelBuilder.Entity<BaseEntity>()
            .Ignore(e => e.NameFull);
        modelBuilder.Entity<BaseEntity>()
            .Ignore(e => e.Age);

BriceLambson wrote Jan 15, 2013 at 6:06 PM

Closing Work Items marked as Done on the Kanban board.

** Closed by BriceLambson 01/15/2013 11:06AM

kraeg wrote Jan 17, 2013 at 5:03 AM

I agree. How is this Low Impact?

We have tried all of the suggestions above and will not be able to make use of Entity Framework 5 unless a patch is released.

RoMiller wrote Jan 17, 2013 at 5:30 PM

RoMiller wrote Jan 17, 2013 at 5:30 PM

** Closed by RoMiller 01/17/2013 10:30AM

RoMiller wrote Jan 17, 2013 at 5:33 PM

@kraeg & @NeRane - Low Impact is just the default when issues are opened, we hadn't updated it for this issue :) I've changed it to medium.

We won't be patching EF5 with this fix because there is a simple workaround. As NeRane mentioned you can use the fluent API rather than an annotation.

AndriySvyryd wrote Jan 18, 2013 at 9:06 PM

@kraeg: If you have tried all workarounds on this page and still running into this exception then send me the smallest part of your project that exhibits this behavior.

nalvest wrote Jan 23, 2013 at 9:17 PM

I still have this problem with EF 5.

I can't use the workaround because I have a slightly different case. I've changed your model slightly below which reflects my case. We have a single abstract class all of our entities inherit from and that base entity class doesn't have a primary key. Thus I can't include the base abstract class as it doesn't have a key property and I can't ignore it as I get this exception.

var modelBuilder = new DbModelBuilder();
modelBuilder.Entity<DerivedEntity>();
modelBuilder.Entity<BaseEntity>();
modelBuilder.Build(new DbProviderInfo("System.Data.SqlClient", "2008"));

public class BaseEntity
{
[NotMapped]
public string BaseProperty { get; set; }
}

public class DerivedEntity : BaseEntity
{
public long Id { get; set; }
}

public class DerivedEntity : BaseEntity
{
public long PrimaryKey { get; set; }
}

AndriySvyryd wrote Feb 22, 2013 at 5:10 PM

@nalvest: In your case the workaround is to use Ignore on every derived entity.
            modelBuilder.Entity<DerivedEntity>().Ignore(e => e.BaseProperty);

mitypatel wrote Mar 19, 2013 at 2:57 PM

@RoMiller I don't understand why you can't patch EF5. From what I've seen, it's a one/ two line change your end. For me it's a nightmare!!! I have to individually go through each entity and ignore all the properties using model builder.

Isn't that the entire point of using attributes in the first place. So you don't have to manually code using fluent.

EF 5 is meant to be a release. Not a half finished release. Most people using SQL Server can ignore and go straight to EF 6 alpha. We on the other hand are not using SQL Server so are stuck with many lines of workaround code until EF 6 is released.

Not helpful!!!!

mitypatel wrote Mar 19, 2013 at 2:59 PM

Just to add to my rant below, EF 4 was patched to 4.1 and then 4.3.1. Why not EF 5.1 or similar?

JoshM_S3 wrote Apr 18, 2013 at 6:04 PM

This is marked Closed instead of Resolved, does that mean it is not fixed in the current EF6 alpha release?

AndriySvyryd wrote Apr 18, 2013 at 8:38 PM

@JoshM_S3 It is fixed in all EF6 alpha releases.

DabblerNL wrote May 9, 2013 at 5:19 PM

I must agree that this should have been patched. When the excluded property is in an abstract base class that is not mapped to a table, the only workaround is to add Ignore statements for ALL your entities. Ouch!

Merlim00 wrote Jun 18, 2013 at 12:07 PM

I've followed the workaround procedure, but it still does not work.

BaseObject is abstract and have a property State that I would like to exclude. BaseObject should not have it's own table.

modelBuilder.ComplexType<BaseObject>().Ignore(p => p.State);
modelBuilder.Ignore<BaseObject>();

does not work -> Invalid Column Name when trying to use the DAL

modelBuilder.Entity<BaseObject>().Ignore(p => p.State);
modelBuilder.Ignore<BaseObject>();

does not work -> Invalid Column Name when trying to use the DAL

Ignore(p => p.State); withing a ComplexTypeConfiguration<BaseObject> or EntityTypeConfiguration<BaseObject>

does not work -> Invalid Column Name when trying to use the DAL

Type[] types = Assembly.GetAssembly(typeof(BaseObject)).GetTypes();
        foreach (Type type in types)
        {
            if (type.IsSubclassOf(typeof(BaseObject)))
            {
                MethodInfo entityMethod = typeof(DbModelBuilder).GetMethod("Entity").MakeGenericMethod(type);
                MethodInfo ignoreMethod = typeof(EntityTypeConfiguration<>).MakeGenericType(type).GetMethod("Ignore").MakeGenericMethod(typeof(ObjectState));

                ParameterExpression parameter = Expression.Parameter(type, "p");
                MemberExpression property = Expression.Property(parameter, "State");
                var delegateType = typeof(Func<,>).MakeGenericType(type, typeof(ObjectState));

                var entityTypeConfiguration = entityMethod.Invoke(modelBuilder, null);
                var stateExpression = Expression.Lambda(delegateType, property, parameter);
                ignoreMethod.Invoke(entityTypeConfiguration, new object[] { stateExpression });
            }
        }
Basically doing modelBuilder.Entity<W>.Ignore(p => p.State)
does not work --> You cannot use Ignore method on the property 'State' on type 'W' because this type inherits from the type 'BaseObject' where this property is mapped. To exclude this property from your model, use NotMappedAttribute or Ignore method on the base type.

iCeDFiRe wrote Jul 22, 2013 at 9:25 AM

Hey!

I might have found a solution, for those who are still blocked by that issue. I was experiencing the exact same problems, after conversion from EF 4.3.1 to EF 4.5, with a derived-base class data structure.

I realizaed that in the OnModelCreating method, the member modelBuilder.Configurations._entityConfigurations (private member) was listing the entity types in an order in which the derived type came BEFORE the base type. In fact, the order in that list is the order as defined in the DbContext derived type, when you create all your DbSet<EntityX> properties.

So, what I did: I moved the base type BEFORE the derived type (i mean the DbSet of the base type before the DbSet of the derived type) and it fixed my problem!

After that, the NotMapped attribute in the base class was sufficient to avoid any issue.

Hope this workaround will help others!

lelong37 wrote Jul 29, 2013 at 3:48 PM

FYI, this works fine, EF6, just marking it with [NotMapped] attribute however does not work with modelBuilder.Entity<EntityBase>().Ignore(t => t.State);

BriceLambson wrote Jan 20, 2014 at 7:18 PM

Fixed in changeset 25d5ead4ddb0545164a9ecab60959ea558a64a05

msanaei wrote Jul 20, 2014 at 7:48 PM

I'm using ef 6.1 but when I use following code, get the same error:

modelBuilder.Types().Configure(c => c.Ignore("IsDeleted"));
I think this bug does not fix yet.

AntonH wrote Nov 29, 2014 at 11:27 PM

It seems like there is still a problem with ignoring base-class defined properties in EF 6.1, we are still forced to use the [NotMapped] workaround which is not a good solution for those who do not want to pollute their domain model with persistence-related attributes.

Please also note that there are people out there in the world who are using fluent/configuration-based mappings, and this case is not considered here at all!

AlirezaHaghshenas wrote Dec 1, 2014 at 4:21 AM

@Antonh This behavior is by design. EF is expected to respect inheritance and map it to relational databases.

brettpostin wrote Nov 16, 2015 at 2:37 PM

This is still occurring in 6.1.3 using the Fluent API. None of the workarounds work either.

AndriySvyryd wrote Nov 16, 2015 at 9:46 PM

If the issue still occurs for you please post a complete repro in a new issue.

KSaeedi wrote Dec 16, 2016 at 4:32 PM

A Workaround that Helped Me

Part of the domain model of my project consists of the following structure:
public enum PocoState { ... }

public abstract class User {
  public PocoState PocoState { get; set; } // should not be mapped
}

public class Employee : User{}

public class Customer : User{}
I have configuration classes derived from EntityTypeConfiguration class in a separate assembly as follows:
public class UserConfig : EntityTypeConfiguration<User>
{
    Ignore(p => p.PocoState);
}

public class EmployeeConfig : EntityTypeConfiguration<Employee>
{
    public EmployeeConfiguration()
    {
        // All needed configurations except Ignore(p => p.PocoState)
    }
}

public class CustomerConfiguration : EntityTypeConfiguration<Customer>
{
    public CustomerConfiguration()
    {
        // All needed configurations except Ignore(p => p.PocoState)
    }
}
Then I add these configuration classes to the OnModelCreating method inside DbContext class.

My DbContext class is like below
public class MyDbContext : DbContext
{
    public DbSet<Employee> Employees { get; set; }
    public DbSet<Customer> Customers { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.AddFromAssembly(Assembly.GetAssembly(typeof(UserConfig)));
        base.OnModelCreating(modelBuilder);
    }
}
HTH

KSaeedi wrote Dec 16, 2016 at 4:36 PM

In the above example I forgot to put the code ijnside the ctor of the UserConfig class. Please consider the following code as the correct fragment:
public class UserConfig : EntityTypeConfiguration<User>
{
    public UserConfig()
    {
        Ignore(p => p.PocoState);
    }
}