0

When using Entity Framework 5 Code First, with Table Per Hierarchy. This combined with a Repository and Unit of Work (tried several implementations). I'm having the following error:

(34,10) : error 3032: Problem in mapping fragments starting at lines 19, 34:EntityTypes T, T are being mapped to the same rows in table T. Mapping conditions can be used to distinguish the rows that these types are mapped to.

I have resolved this issue using the following guide: Entity Framework 4.3 - TPH mapping and migration error

This works when using a general look-up of all records, then no errors.

When using the DBSet<T>.Find(id), I receive the above error message.

When using DBSet<T>.Where(t => t.id == id) all works fine.

Please does anyone have the solution for this problem?

public class TDataContext : DbContext
{
    // Models
    public abstract class BaseTrackable
    {
        public DateTime DateModified { get; set; }
    }

    public abstract class ParentClass : BaseTrackable
    {
        public int ParentId { get; set; }
        public string ParentString { get; set; }
    }

    public class Foo : ParentClass
    {
        public string FooString { get; set; }
    }

    public class Bar : ParentClass
    {
        public string BarString { get; set; }
    }

    // Configuration
    public class ParentConfiguration : EntityTypeConfiguration<ParentClass>
    {
        public ParentConfiguration()
        {
            ToTable("Parent");
        }
    }

    public class FooConfiguration : EntityTypeConfiguration<Foo>
    {
        public FooConfiguration()
        {
            Map(m => m.Requires("FooIndicator").HasValue(true));
        }
    }

    public class BarConfiguration : EntityTypeConfiguration<Bar>
    {
        public BarConfiguration()
        {
            Map(m => m.Requires("BarIndicator").HasValue(true));
        }
    }

    public DbSet<ParentClass> Parent { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations
            .Add(new ParentConfiguration())
            .Add(new FooConfiguration())
            .Add(new BarConfiguration());
    }

}

public class Controller
{
    TDataContext _context = new TDataContext();

    // Repository function
    public T GetById<T>(object id) where T : class 
    {
        var dbset = _context.Set<T>();
        return dbset.Find(id);
    }

    public IQueryable<TDataContext.Foo> GetFiltered(Expression<Func<TDataContext.Foo, bool>> filter) 
    {
        var dbset = _context.Set<TDataContext.Foo>();
        return dbset.Where(filter);
    }

    // Final call
    // Which fails..
    public TDataContext.Foo Get(int id)
    {
        return this.GetById<TDataContext.Foo>(id);
    }

    // This works...
    public TDataContext.Foo GetWhere(int id)
    {
        return this.GetFiltered(f => f.ParentId == id).FirstOrDefault();
    }
}
Community
  • 1
  • 1
PJong
  • 98
  • 1
  • 6
  • Can you post some code. This works without any problem. It looks like not all your types in TPH are correctly mapped with discriminator value. – Ladislav Mrnka Aug 18 '12 at 08:26
  • In TPH the `ParentClass` must be mapped to the same table as children and it must be configured with discriminator. – Ladislav Mrnka Aug 18 '12 at 08:52
  • Hi Ladislav, this is done using the Map(m => m.Requires("Indicator").HasValue(true)) – PJong Aug 18 '12 at 08:56

2 Answers2

0

Found something that solves my problem partially...

When adding another indicator to the tables, there is no more error, example:

public class FooConfiguration : EntityTypeConfiguration<Foo>
    {
        public FooConfiguration()
        {
            Map(m => {
                m.Requires("FooIndicator").HasValue(true);
                m.Requires("BarIndicator").HasValue<short>(1);
            });
        }
    }

    public class BarConfiguration : EntityTypeConfiguration<Bar>
    {
        public BarConfiguration()
        {
            Map(m => {
                m.Requires("BarIndicator").HasValue(true);
                m.Requires("FooIndicator").HasValue<short>(0);
            });
        }
    }
PJong
  • 98
  • 1
  • 6
0

Wouldn't be better

public class FooConfiguration : EntityTypeConfiguration<Foo> 
{ 
    public FooConfiguration() 
    { 
        Map(m => m.Requires("Type").HasValue("Foo")); 
    } 
} 

public class BarConfiguration : EntityTypeConfiguration<Bar> 
{ 
    public BarConfiguration() 
    { 
        Map(m => m.Requires("Type").HasValue("Bar"); 
    } 
}

In this way FooConfiguration doesn't need to know anything about BarConfiguration and visa versa. I had this issue when migrating from EF 4.3 to 5.0 and I think what has changed was the discriminator database columns are not nullable in EF 5.0. I think it makes much more sense for them to be not nullable and in general it might be better to have only one discrimanotor column for each derived type as opposed to one column per type (as it was in EF 4.3)

-Stan

Stan Bashtavenko
  • 1,025
  • 11
  • 16