Entity Framework 4 CTP 5 Self Referencing Many-to-Many
Asked Answered
W

1

8

I have the following scenario in my database. It is a record of Studies and those studies have other studies as prerequisites. In my DB design, it looks like this:

self referencing many to many

And my code looks something like this:

public class Study
{
    public int ID { get; set; }
    public string Topic { get; set; }
    public byte TypeID { get; set; }
    public virtual StudyType Type { get; set; }
    public bool Deprecated { get; set; }

    public virtual ICollection<Study> Prerequisites { get; set; }
}

public class StudyType
{
    public byte ID { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Study> Studies { get; set; }
}

public class MyContext : DbContext
{

    public DbSet<Study> Studies { get; set; }
    public DbSet<StudyType> StudyTypes { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Study>()
            .HasMany(p=>p.Prerequisites)
            .WithMany().Map(ps =>
                {
                    ps.ToTable("Prerequisites");
                    ps.MapLeftKey(x=>x.ID,"StudyID");
                    ps.MapRightKey(y=>y.ID,"PrerequisiteID");
                });
    }

I'm not super good at the EF syntax, but from what I've found Googling, that seems like it should work. Instead, I get Sequence contains more than one matching element.

I found this, but since the entity is referencing itself, I can't exactly rename the key field in only one of the tables: http://social.msdn.microsoft.com/Forums/eu/adonetefx/thread/745a2c4f-cb66-41ad-9524-15aa198c40c7

Anybody help me through this?

EDIT

Here is the full stack trace of the exception:

It executes on a line of LINQ: var x = from s in db.Studies select s;

Server stack trace: 
 at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
 at System.Data.Entity.ModelConfiguration.Configuration.Properties.Navigation.ManyToManyAssociationMappingConfiguration`2.Configure(DbAssociationSetMapping associationSetMapping)
 at System.Data.Entity.ModelConfiguration.Configuration.Properties.Navigation.NavigationPropertyConfiguration.Configure(DbDatabaseMapping databaseMapping)
 at System.Data.Entity.ModelConfiguration.Utilities.IEnumerableExtensions.Each[T](IEnumerable`1 ts, Action`1 action)
 at System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.ConfigureAssociationMappings(DbDatabaseMapping databaseMapping)
 at System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.Configure(DbEntityTypeMapping entityTypeMapping, DbDatabaseMapping databaseMapping, DbProviderManifest providerManifest)
 at System.Data.Entity.ModelConfiguration.Configuration.ModelConfiguration.Configure(DbDatabaseMapping databaseMapping, DbProviderManifest providerManifest)
 at System.Data.Entity.ModelConfiguration.ModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo, Boolean validateModel)
 at System.Data.Entity.ModelConfiguration.ModelBuilder.Build(DbConnection providerConnection)
 at System.Data.Entity.Internal.LazyInternalContext.CreateModel()
 at System.Lazy`1.CreateValue()

Exception rethrown at [0]: 
 at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
 at System.Data.Entity.ModelConfiguration.Configuration.Properties.Navigation.ManyToManyAssociationMappingConfiguration`2.Configure(DbAssociationSetMapping associationSetMapping)
 at System.Data.Entity.ModelConfiguration.Configuration.Properties.Navigation.NavigationPropertyConfiguration.Configure(DbDatabaseMapping databaseMapping)
 at System.Data.Entity.ModelConfiguration.Utilities.IEnumerableExtensions.Each[T](IEnumerable`1 ts, Action`1 action)
 at System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.ConfigureAssociationMappings(DbDatabaseMapping databaseMapping)
 at System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.Configure(DbEntityTypeMapping entityTypeMapping, DbDatabaseMapping databaseMapping, DbProviderManifest providerManifest)
 at System.Data.Entity.ModelConfiguration.Configuration.ModelConfiguration.Configure(DbDatabaseMapping databaseMapping, DbProviderManifest providerManifest)
 at System.Data.Entity.ModelConfiguration.ModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo, Boolean validateModel)
 at System.Data.Entity.ModelConfiguration.ModelBuilder.Build(DbConnection providerConnection)
 at System.Data.Entity.Internal.LazyInternalContext.CreateModel()
 at System.Lazy`1.CreateValue()
 at System.Lazy`1.LazyInitValue()
 at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
 at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
 at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
 at System.Data.Entity.Internal.Linq.InternalSet`1.get_Provider()
 at System.Linq.Queryable.Select[TSource,TResult](IQueryable`1 source, Expression`1 selector)
 at DataAccess.Sql.SqlStudyRepository.GetAll() in C:\Side Work\Rephidim Church\Tuchikos 2011\Program\DataAccess\Sql\SqlStudyRepository.cs:line 22
 at API.Controllers.StudiesController.Index() in C:\Side Work\Rephidim Church\Tuchikos 2011\Program\API\Controllers\StudiesController.cs:line 24
 at lambda_method(Closure , ControllerBase , Object[] )
 at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
 at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
 at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12()
 at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
Waiver answered 12/2, 2011 at 23:11 Comment(6)
What is the full stack for the error, and which line of code is throwing?Robbirobbia
Edited question to include stack trace.Waiver
Gosh, that stack looks familiar. I think you may be hitting a CTP bug. See my comments there.Robbirobbia
@Craig Stuntz is there somewhere the development version of ctp, so that we could use the latest dev version ?Overcritical
yNo, there isn't. Not unless you work for Microsoft.Robbirobbia
What happens here: var x = from s in db.Studies select s.First()Smooth
J
0

This is what I have in an EntityTypeConfiguration<> implementation for a similar situation in CTP5.

HasMany(g => g.SubGroups)
    .WithMany(g => g.ParentGroups)
    .Map(m => m.ToTable("Groups_SubGroups"));

Not sure exactly how that translates to configuring the DbContext directly, but I imagine it should be close.

If memory serves, LeftKey() RightKey() syntax wasn't quite there in CTP5, so you just have to use the default column names that it creates or is expecting. In my case, it is GroupId and GroupId1. That follows the pattern <class>Id and <class>Id1, not <field> and <field>1 by the way.

The error that you're getting does seem familiar and I don't remember that the solution was obvious in any way. But, I did set this all up a while ago so the memories of how I arrived at something that works is a bit swiss cheesed. Hope it helps some.

Jaela answered 15/4, 2011 at 19:7 Comment(2)
I'll definitely test it out. Haven't been on this particular project in a while, so I'll have to get back into it a bit. And now that the RTW is out for EF 4.1, the preferred way may be different.Waiver
Aye, not sure why this question came up first thing when looking at questions. I posted and then saw the questions date. Figured I'd leave it up just in case. Figure we'll be changing up to 4.1 soon too.Jaela

© 2022 - 2024 — McMap. All rights reserved.