none
TPC mapping throws NotSupportedException - please help RRS feed

  • Question

  • Hello, I have the following two classes:

    public abstract class Entity { public virtual long Id { get; protected internal set; } public virtual int Version { get; protected internal set; } public virtual DateTime Created { get; protected internal set; } } public class Bank : Entity { public virtual bool IsOriginator { get; protected internal set; } public virtual string Name { get; protected internal set; } public virtual string RoutingNumber { get; protected internal set; } } Here are the configuration classes that map the classes above:

    class EntityConfiguration : EntityTypeConfiguration<Entity>
    {
    	public EntityConfiguration()
    	{
    	    HasKey(e => e.Id);
    	    Property(e => e.Id)
    		.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None)
    		;
    	    Property(e => e.Version)
    		.IsConcurrencyToken()
    		.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None)
    		;
    	    Property(e => e.Created)
    		.HasColumnType("datetime2")
    		.IsRequired()
    		;
    	}
    }
    
    class BankConfiguration : EntityTypeConfiguration<Bank>
    {
    	public BankConfiguration()
    	{
    	    Map(b =>
    		{
    		    b.MapInheritedProperties();
    		    b.ToTable("Bank");
    		});
    	    Property(b => b.Name)
    		.IsRequired()
    		.HasMaxLength(BankConstants.MaxNameLength)
    		;
    	    Property(b => b.IsOriginator)
    		.IsRequired()
    		;
    	    Property(b => b.RoutingNumber)
    		.IsOptional()
    		.HasMaxLength(BankConstants.MaxRoutingNumberLength)
    		;
    	}
    }

    However context.Database.CreateIfNotExists() throws the following exception

    System.NotSupportedException was unhandled by user code
      Message=The type 'Bank' cannot be mapped as defined because it maps inherited properties from types that use entity splitting or another form of inheritance. Either choose a different inheritance mapping strategy so as to not map inherited properties, or change all types in the hierarchy to map inherited properties and to not use splitting.
      Source=EntityFramework
      StackTrace:
           at System.Data.Entity.ModelConfiguration.Conventions.MappingInheritedPropertiesSupportConvention.<>c__DisplayClass3.<System.Data.Entity.ModelConfiguration.Conventions.IDbMappingConvention.Apply>b__1(DbEntitySetMapping esm)
           at System.Data.Entity.ModelConfiguration.Utilities.IEnumerableExtensions.Each[T](IEnumerable`1 ts, Action`1 action)
           at System.Data.Entity.ModelConfiguration.Conventions.MappingInheritedPropertiesSupportConvention.System.Data.Entity.ModelConfiguration.Conventions.IDbMappingConvention.Apply(DbDatabaseMapping databaseMapping)
           at System.Data.Entity.ModelConfiguration.Configuration.ConventionsConfiguration.ApplyMapping(DbDatabaseMapping databaseMapping)
           at System.Data.Entity.DbModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo)
           at System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)
           at System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext)
           at System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input)
           at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
           at System.Data.Entity.Internal.InternalContext.CreateObjectContextForDdlOps()
           at System.Data.Entity.Database.CreateIfNotExists()
           at UnitTests.PaymentElementsServiceTest.TestInitialize() in ...
      InnerException:

    What am I doing wrong? Are there any requirements for the base and inherited classes to be able to TPC map them.


    Thanks Val

    Tuesday, February 7, 2012 11:24 PM

Answers

  • Hi Val,

    It seems ok! Here is my testing code and works on my computer, please test it on your side.

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Entity.ModelConfiguration; using System.ComponentModel.DataAnnotations; using System.Data.Entity; using System.Data.Entity.Infrastructure; namespace FluentAPI { class Program { static void Main(string[] args) { using (var db= new EFRepository() ) { db.Database.CreateIfNotExists(); } } } public abstract class Entity { public virtual long Id { get; protected internal set; } public virtual int Version { get; protected internal set; } public virtual DateTime Created { get; protected internal set; } } public class Bank : Entity { public virtual bool IsOriginator { get; protected internal set; } public virtual string Name { get; protected internal set; } public virtual string RoutingNumber { get; protected internal set; } } class EntityConfiguration : EntityTypeConfiguration<Entity> { public EntityConfiguration() { HasKey(e => e.Id); Property(e => e.Id) .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None) ; Property(e => e.Version) .IsConcurrencyToken() .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None) ; Property(e => e.Created) .HasColumnType("datetime2") .IsRequired(); } } class BankConfiguration : EntityTypeConfiguration<Bank> { public BankConfiguration() { Map(b => { b.MapInheritedProperties(); b.ToTable("Bank"); }); Property(b => b.Name) .IsRequired() .HasMaxLength(100) ; Property(b => b.IsOriginator) .IsRequired() ; Property(b => b.RoutingNumber) .IsOptional() .HasMaxLength(100) ; } } public partial class EFRepository : DbContext { public IDbSet<Bank> Banks { get { return Set<Bank>(); } } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder .Conventions .Remove<IncludeMetadataConvention>(); modelBuilder .Configurations .Add(new EntityConfiguration()) .Add(new BankConfiguration()) ; } } }

    If it couldn't work, please let me know.

    Have a nice day.


    Alan Chen[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, February 9, 2012 6:06 AM
    Moderator

All replies

  • Hi Val,

    Welcome!

    You couldn't put variables in Fluent API(BankConstants.MaxNameLength and BankConstants.MaxRoutingNumberLength), please try to pass int constant value here.

    Have a nice day.


    Alan Chen[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, February 8, 2012 1:18 AM
    Moderator
  • Alan,

    Thank you for your reply. These are not variables but constants. Nevertheless I removed them and replaced with constants - still the same problem... Just to make the picture complete, here are the most important pieces of my context creation:

    public partial class EFRepository : DbContext
    {
    
    	public EFRepository()
    	{
    	}
    
    	public EFRepository(string connectionString)
    	    : base(connectionString)
    	{
    	}
    
    	public IDbSet<Bank> Banks { get { return Set<Bank>(); } }
    
    	protected override void OnModelCreating(DbModelBuilder modelBuilder)
    	{
    	    modelBuilder
    		.Conventions
    		    .Remove<PluralizingTableNameConvention>();
    
    	    modelBuilder
    		.Configurations
    		    .Add(new EntityConfiguration())
    			.Add(new BankConfiguration())
    		;
    	}
    }
    I wonder if ".Add(new EntityConfiguration())" might be the problem...?

    Thanks Val

    Wednesday, February 8, 2012 3:39 PM
  • Hi Val,

    It seems ok! Here is my testing code and works on my computer, please test it on your side.

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Entity.ModelConfiguration; using System.ComponentModel.DataAnnotations; using System.Data.Entity; using System.Data.Entity.Infrastructure; namespace FluentAPI { class Program { static void Main(string[] args) { using (var db= new EFRepository() ) { db.Database.CreateIfNotExists(); } } } public abstract class Entity { public virtual long Id { get; protected internal set; } public virtual int Version { get; protected internal set; } public virtual DateTime Created { get; protected internal set; } } public class Bank : Entity { public virtual bool IsOriginator { get; protected internal set; } public virtual string Name { get; protected internal set; } public virtual string RoutingNumber { get; protected internal set; } } class EntityConfiguration : EntityTypeConfiguration<Entity> { public EntityConfiguration() { HasKey(e => e.Id); Property(e => e.Id) .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None) ; Property(e => e.Version) .IsConcurrencyToken() .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None) ; Property(e => e.Created) .HasColumnType("datetime2") .IsRequired(); } } class BankConfiguration : EntityTypeConfiguration<Bank> { public BankConfiguration() { Map(b => { b.MapInheritedProperties(); b.ToTable("Bank"); }); Property(b => b.Name) .IsRequired() .HasMaxLength(100) ; Property(b => b.IsOriginator) .IsRequired() ; Property(b => b.RoutingNumber) .IsOptional() .HasMaxLength(100) ; } } public partial class EFRepository : DbContext { public IDbSet<Bank> Banks { get { return Set<Bank>(); } } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder .Conventions .Remove<IncludeMetadataConvention>(); modelBuilder .Configurations .Add(new EntityConfiguration()) .Add(new BankConfiguration()) ; } } }

    If it couldn't work, please let me know.

    Have a nice day.


    Alan Chen[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, February 9, 2012 6:06 AM
    Moderator
  • Hi,

    I am writing to check the status of the issue on your side. Would you mind letting us know the result of the suggestions?
    If you need further assistance, please feel free to let me know. I will be more than happy to be of assistance.

    Have a nice day.


    Alan Chen[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, February 15, 2012 8:20 AM
    Moderator
  • I think I get it: almost every time when there is a problem with the configuration I get this exception and the problem usually has nothing to do with the my class Bank or entity splitting, etc. This looks to me like a catch-all exception. I doubt it that the initial intention was that but surely feels that way... Is it possible to fix the message or throw different exceptions with more appropriate message texts? I am sure you guys are in a freeze mode already and are working hard on Win8 and other hot projects but this is a serious productivity killer and a source of frustration... Manual, fluid configuration is a wonderful thing but is error prone (nevertheless I refuse to use the UI tools! :)) but your help will be highly appreciated here.

    Val


    Thanks Val

    Sunday, June 24, 2012 10:25 PM