如何解决实体框架如何使两个外键引用同一个表
我需要创建一个表,该表由 2 个引用相同模型/表的外键组成。我尝试了很多方法,比如为同一个表的每个外键创建一个自己的 ICollection,或者使用 Inverseproperty 和 fluentapi 但它从来没有奏效(总是出错)。
我真正需要的(我也尝试过上述选项)是: 我的表 1:
using Messanger_Backend.SideClasses;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
namespace Messanger_Backend.Models
{
[Index(nameof(User.UserPhoneNumber),IsUnique = true)]
public class User : BaseEntity
{
public User()
{
UserMessages = new HashSet<UserMessage>();
}
[Key]
public int UserID { get; set; }
[Column(TypeName="nvarchar(50)")]
public string UserFirstname { get; set; }
[Column(TypeName = "nvarchar(50)")]
public string UserLastname { get; set; }
[Column(TypeName = "nvarchar(20)")]
[required]
public string UserPhoneNumber { get; set; }
public ICollection<UserMessage> UserMessages { get; set; }
}
}
我的桌子 2:
using Messanger_Backend.SideClasses;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
namespace Messanger_Backend.Models
{
public class UserMessage : BaseEntity
{
[Key]
public int UserMessageID { get; set; }
public int UserMessageSenderID { get; set; }
public User UserMessageSender { get; set; }
public int UserMessageReceiverID { get; set; }
public User UserMessageReceiver { get; set; }
[Column(TypeName="nvarchar(500)")]
public string UserMessageText { get; set; }
}
}
更新 我尝试了@David browne - 微软的建议,但我也没有工作。这是我尝试过的方法:
用户:
using Messanger_Backend.SideClasses;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
namespace Messanger_Backend.Models
{
[Index(nameof(User.UserPhoneNumber),IsUnique = true)]
public class User : BaseEntity
{
public User()
{
UserMessagesSender = new HashSet<UserMessage>();
UserMessagesReceiver = new HashSet<UserMessage>();
}
[Key]
public int UserID { get; set; }
[Column(TypeName="nvarchar(50)")]
public string UserFirstname { get; set; }
[Column(TypeName = "nvarchar(50)")]
public string UserLastname { get; set; }
[Column(TypeName = "nvarchar(20)")]
[required]
public string UserPhoneNumber { get; set; }
[Column(TypeName = "nvarchar(250)")]
public string UserStatus { get; set; }
[InverseProperty("UserMessageSenderID")]
public virtual ICollection<UserMessage> UserMessagesSender { get; set; }
[InverseProperty("UserMessagesReceiverID")]
public virtual ICollection<UserMessage> UserMessagesReceiver { get; set; }
}
}
```
UserMessage:
```
using Messanger_Backend.SideClasses;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
namespace Messanger_Backend.Models
{
public class UserMessage : BaseEntity
{
[Key]
public int UserMessageID { get; set; }
public int UserMessageSenderID { get; set; }
[ForeignKey("UserMessageSenderID")]
public User UserMessageSender { get; set; }
public int UserMessageReceiverID { get; set; }
[ForeignKey("UserMessageReceiverID")]
public User UserMessageReceiver { get; set; }
[Column(TypeName="nvarchar(500)")]
public string UserMessageText { get; set; }
[Column(TypeName = "DateTime")]
public DateTime UserMessageReceived { get; set; }
[Column(TypeName = "DateTime")]
public DateTime UserMessageRead { get; set; }
}
}
```
Error I receive on second option:
PM> Add-Migration "Init Migration"
Build started...
Build succeeded.
system.invalidOperationException: The [InverseProperty] attribute on property 'User.UserMessagesReceiver' is not valid. The property 'UserMessagesReceiverID' is not a valid navigation on the related type 'UserMessage'. Ensure that the property exists and is a valid reference or collection navigation.
at Microsoft.EntityFrameworkCore.Metadata.Conventions.InversePropertyAttributeConvention.ConfigureInverseNavigation(IConventionEntityTypeBuilder entityTypeBuilder,MemberInfo navigationMemberInfo,IConventionEntityTypeBuilder targetEntityTypeBuilder,InversePropertyAttribute attribute)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.InversePropertyAttributeConvention.Process(IConventionEntityTypeBuilder entityTypeBuilder,Type targetClrType,InversePropertyAttribute attribute)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.InversePropertyAttributeConvention.ProcessEntityTypeAdded(IConventionEntityTypeBuilder entityTypeBuilder,InversePropertyAttribute attribute,IConventionContext`1 context)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.NavigationAttributeConventionBase`1.ProcessEntityTypeAdded(IConventionEntityTypeBuilder entityTypeBuilder,IConventionContext`1 context)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.Conventiondispatcher.ImmediateConventionScope.OnEntityTypeAdded(IConventionEntityTypeBuilder entityTypeBuilder)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.Conventiondispatcher.OnEntityTypeAddednode.Run(Conventiondispatcher dispatcher)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.Conventiondispatcher.DelayedConventionScope.Run(Conventiondispatcher dispatcher)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.Conventiondispatcher.ConventionBatch.Run()
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.Conventiondispatcher.ConventionBatch.dispose()
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.Conventiondispatcher.ImmediateConventionScope.OnModelInitialized(IConventionModelBuilder modelBuilder)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.Conventiondispatcher.OnModelInitialized(IConventionModelBuilder modelBuilder)
at Microsoft.EntityFrameworkCore.Metadata.Internal.Model..ctor(ConventionSet conventions,ModelDependencies modelDependencies)
at Microsoft.EntityFrameworkCore.ModelBuilder..ctor(ConventionSet conventions,ModelDependencies modelDependencies,Boolean _)
at Microsoft.EntityFrameworkCore.ModelBuilder..ctor(ConventionSet conventions,ModelDependencies modelDependencies)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context,IConventionSetBuilder conventionSetBuilder,ModelDependencies modelDependencies)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context,ModelDependencies modelDependencies)
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_3(IServiceProvider p)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite,RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite,TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite,RuntimeResolverContext context,ServiceProviderEnginescope serviceProviderEngine,RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite,RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite,TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite,TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite,ServiceProviderEnginescope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__displayClass1_0.<RealizeService>b__0(ServiceProviderEnginescope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType,ServiceProviderEnginescope serviceProviderEnginescope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEnginescope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetrequiredService(IServiceProvider provider,Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetrequiredService[T](IServiceProvider provider)
at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure`1 accessor)
at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func`1 factory)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name,String outputDir,String contextType,String namespace)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name,String namespace)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__displayClass0_0.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__displayClass3_0`1.<Execute>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
The [InverseProperty] attribute on property 'User.UserMessagesReceiver' is not valid. The property 'UserMessagesReceiverID' is not a valid navigation on the related type 'UserMessage'. Ensure that the property exists and is a valid reference or collection navigation.
解决方法
InverseProperty
指的是导航属性,而不是外键属性,并缩短导航属性名称,例如 Sender
而不是 UserMessageSender
。所以像
[InverseProperty("Sender")]
public virtual ICollection<UserMessage> MessagesSent { get; set; }
[InverseProperty("Receiver")]
public virtual ICollection<UserMessage> MessagesReceived { get; set; }
在 .NET 中,在属性名称中预置类型名称是不常见的,而在列名中预置其表名则更为常见。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。