EF - 无法确定关系

时间:2017-05-02 13:52:51

标签: c# sql-server entity-framework asp.net-core

我正在制作一个奇幻游戏应用程序。现在一个团队可以有多个玩家,但也有多个用户(比如联盟)。当我尝试将一个集合添加到团队表时,我收到以下错误 (见下文) 。 我试图在网上找到解决方案,似乎这个问题是由多对多的关系引起的。但是,我不知道这是怎么可能的。团队可以拥有许多用户,但用户只能拥有一个团队。 解决方案是创建一个连接表,但为什么我会在每个表上创建一个列以指向包含数据的连接表,当我可以让每个表上的列连接到另一个表时? 有谁知道是什么导致了这个错误以及如何修复它?

System.InvalidOperationException: Unable to determine the relationship represented by navigation property 'Team.Manager' of type 'User'. Either manually configure the relationship, or ignore this property from the model.    at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.PropertyMappingValidationConvention.Apply(InternalModelBuilder modelBuilder)
    at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelBuilt(InternalModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator)
    at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
    at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
    at Microsoft.EntityFrameworkCore.Internal.LazyRef`1.get_Value() 
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass16_0.<RealizeService>b__0(ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitTransient(TransientCallSite transientCallSite, ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitTransient(TransientCallSite transientCallSite, ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass16_0.<RealizeService>b__0(ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.EntityFrameworkCore.Design.MigrationsOperations.AddMigration(String name, String outputDir, String contextType)
    at Microsoft.EntityFrameworkCore.Tools.Cli.MigrationsAddCommand.Execute(CommonOptions commonOptions, String name, String outputDir, String context, String environment, Action`1 reporter)
    at Microsoft.EntityFrameworkCore.Tools.Cli.MigrationsAddCommand.<>c__DisplayClass0_0.<Configure>b__0()
    at Microsoft.Extensions.CommandLineUtils.CommandLineApplication.Execute(String[] args) 
   at Microsoft.EntityFrameworkCore.Tools.Cli.Program.Main(String[] args)
 Unable to determine the relationship represented by navigation property 'Team.Manager' of type 'User'. Either manually configure the relationship, or ignore this property from the model. 

Team.cs

public class Team
{
    [Key]
    public int ID { get; set; }
    public int ManagerID { get; set; }
    public string Name { get; set; }

    [ForeignKey("ManagerID")]
    public virtual User Manager { get; set; }
    public virtual ICollection<Player> Players { get; set; }
    // Unable to determine the relationship represented by navigation property 'Team.Manager' of type 'User'
    public virtual ICollection<User> TeamMebers { get; set; }


    public Team()
    {
        TeamMebers = new List<User>();
        Players = new List<Player>();
    }
}

User.cs

public class User
{
    [Key]
    public int ID { get; set; }
    public int? TeamID { get; set; }
    public string UserName { get; set; }
    public string Name { get; set; }
    public bool ShowAsPm { get; set; }
    public string Deactiviated { get; set; }

    [ForeignKey("TeamID")]
    public virtual Team Team { get; set; }
    // How many hours they played 
    public virtual ICollection<Log> Hours { get; set; }

    public User()
    {
        Hours = new List<Log>();
    }
}

Log.cs

public class Log
{
    [Key]
    public int ID { get; set; }
    public int? GameID { get; set; }
    public int? ResultID { get; set; }
    public int? UserID { get; set; }

    public string SmNumber { get; set; }
    public decimal? Duration { get; set; }
    public DateTime LogDate { get; set; }

    [ForeignKey("GameID")]
    public virtual Game Game { get; set; }
    [ForeignKey("ResultID")]
    public virtual GameResult Result { get; set; }
    [ForeignKey("UserID")]
    public virtual User User { get; set; }

    public Log() { }
}

Context.cs

protected override void OnModelCreating(ModelBuilder builder)
{
     //builder.Entity<Team>().HasMany(t => t.TeamMebers).WithOne(u => u.Team).HasForeignKey(u => u.ID);
    //builder.Entity<User>().HasOne(u => u.Team).WithMany(t => t.TeamMebers).HasForeignKey(t => t.ID);
    builder.Entity<Team>().ToTable("Teams");
    builder.Entity<User>().ToTable("Users");
    builder.Entity<Log>().ToTable("Logs");
}

更新

protected override void OnModelCreating(ModelBuilder builder)
{
    builder.Entity<Team>().ToTable("Teams");
    builder.Entity<User>().ToTable("Users");
    builder.Entity<User>().HasOne(u => u.Team).WithMany(u => u.TeamMebers);
    builder.Entity<Log>().ToTable("Logs");
}

例外

System.InvalidOperationException: The current CSharpHelper cannot scaffold literals of type 'System.Collections.Immutable.ImmutableSortedDictionary`2[System.Reflection.PropertyInfo,System.Type]'. Configure your services to use one that can.    at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpHelper.UnknownLiteral(Object value)
    at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateAnnotation(IAnnotation annotation, IndentedStringBuilder stringBuilder)
   at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateEntityTypeAnnotations(IEntityType entityType, IndentedStringBuilder stringBuilder)
   at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateEntityType(String builderName, IEntityType entityType, IndentedStringBuilder stringBuilder)
    at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.GenerateEntityTypes(String builderName, IReadOnlyList`1 entityTypes, IndentedStringBuilder stringBuilder) 
   at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpSnapshotGenerator.Generate(String builderName, IModel model, IndentedStringBuilder stringBuilder)
   at Microsoft.EntityFrameworkCore.Migrations.Design.CSharpMigrationsGenerator.GenerateMetadata(String migrationNamespace, Type contextType, String migrationName, String migrationId, IModel targetModel)
   at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.ScaffoldMigration(String migrationName, String rootNamespace, String subNamespace)
    at Microsoft.EntityFrameworkCore.Design.MigrationsOperations.AddMigration(String name, String outputDir, String contextType)
    at Microsoft.EntityFrameworkCore.Tools.Cli.MigrationsAddCommand.Execute(CommonOptions commonOptions, String name, String outputDir, String context, String environment, Action`1 reporter) 
    at Microsoft.EntityFrameworkCore.Tools.Cli.MigrationsAddCommand.<>c__DisplayClass0_0.<Configure>b__0()
    at Microsoft.Extensions.CommandLineUtils.CommandLineApplication.Execute(String[] args) 
   at Microsoft.EntityFrameworkCore.Tools.Cli.Program.Main(String[] args)
 The current CSharpHelper cannot scaffold literals of type 'System.Collections.Immutable.ImmutableSortedDictionary`2[System.Reflection.PropertyInfo,System.Type]'. Configure your services to use one that can. 

1 个答案:

答案 0 :(得分:6)

您遇到的例外情况解释了您的情况的“问题”:

Unable to determine the relationship represented by navigation property 'Team.Manager' of type 'User'. Either manually configure the relationship, or ignore this property from the model.

解决方案,正如消息所暗示的那样是手动定义这种关系。

builder.Entity<User>().HasOne(u => u.Team).WithMany(u => u.TeamMembers);

但是,这并不能完全解决您的问题,因为这并不能解决其中一个成员是管理员的问题。

更好的解决方案是使用以下中间类来处理关系,同时还将其中一个成员标记为Manager。这仍然无法解决每个团队单个管理员约束的问题,但它会更加接近。

public class TeamMember {
    public int MemberId {get;set;}
    public int TeamId {get;set;}
    public bool IsManager {get;set;}

    public virtual User Member {get;set;}
    public virtual Team Team {get;set;}
}
//Either add an ID or use fluent API to define the key to be a combination of player/teamid