Entity Framework 4 CTP 5 Self Referencing Many-to-Many

爷,独闯天下 提交于 2019-12-18 02:49:38

问题


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:

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)

回答1:


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.



来源:https://stackoverflow.com/questions/4981228/entity-framework-4-ctp-5-self-referencing-many-to-many

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!