Double Relation One to Many(different属性sameClass),无法确定导航所代表的关系,C#
Double Relation One to Many (different Property same Class), Unable to determine the relationship represented by navigation, C#
我想使用 List
在 NxProperty
自定义 class 和 NxLog
自定义 class 之间建立双重关系。
public class NxLog
{
public string NxLogId { get; set; }
public string NxWorkspaceId { get; set; }
public string NxConversationId { get; set; }
public NxConversation NxConversation { get; set; }
public List<NxOutputText> NxOutputTexts { get; set; }
public List<NxProperty> RequestProperties { get; set; } //1st Relation
public List<NxProperty> ResponseProperties { get; set; } //2nd Relation
}
public class NxProperty
{
public string NxPropertyId { get; set; }
public string NxWorkspaceId { get; set; }
public string NxConversationId { get; set; }
public string NxLogId { get; set; }
public NxLog NxLog { get; set; }
public JToken Value { get; set; }
}
在DbContext
女儿class我有:
class CustomDbContext:DbContext
{
DbSet<NxWorkspace> Workspaces { get; set; }
DbSet<NxConversation> Conversations { get; set; }
DbSet<NxLog> Logs { get; set; }
DbSet<NxOutputText> OutputTexts { get; set; }
DbSet<NxProperty> RequestProperties { get; set; }
DbSet<NxProperty> ResponseProperties { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<NxWorkspace>().HasKey(w => w.NxWorkspaceId);
modelBuilder.Entity<NxConversation>().HasKey(c => new { c.NxWorkspaceId, c.NxConversationId });
modelBuilder.Entity<NxLog>().HasKey(l => new { l.NxWorkspaceId, l.NxConversationId, l.NxLogId });
modelBuilder.Entity<NxOutputText>().HasKey(o => new { o.NxWorkspaceId, o.NxConversationId, o.NxLogId, o.NxOutputTextId });
modelBuilder.Entity<NxProperty>().HasKey(p => new { p.NxWorkspaceId, p.NxConversationId, p.NxLogId, p.NxPropertyId });
modelBuilder.Entity<NxProperty>().Property(l => l.Value)
.HasConversion<string>(
o => JsonConvert.SerializeObject(o),
d => JsonConvert.DeserializeObject<JToken>(d)
);
//Other steps
}
}
但我得到了异常:
System.InvalidOperationException: Unable to determine the relationship represented by navigation 'NxLog.RequestProperties' of type 'List<NxProperty>'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidatePropertyMapping(IModel model, IDiagnosticsLogger`1 logger)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
at Microsoft.EntityFrameworkCore.SqlServer.Internal.SqlServerModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.ValidatingConvention.ProcessModelFinalized(IModel model)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalized(IModel model)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalized(IModel model)
at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel()
at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel()
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, ModelDependencies modelDependencies)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder, 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, 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.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 outputDir, String contextType, 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)
Unable to determine the relationship represented by navigation 'NxLog.RequestProperties' of type 'List<NxProperty>'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
PM>
我需要确保我有正确的代码。
我正在尝试
modelBuilder.Entity<NxLog>()
.HasMany(l => l.RequestProperties)
.WithOne(p => p.NxLog).HasForeignKey(p => p.NxLogId);
modelBuilder.Entity<NxLog>()
.HasMany(l => l.ResponseProperties)
.WithOne(p => p.NxLog).HasForeignKey(p => p.NxLogId);
但我明白了...
Cannot create a relationship between 'NxLog.ResponseProperties' and 'NxProperty.NxLog'
because a relationship already exists between 'NxLog.RequestProperties' and 'NxProperty.NxLog'.
Navigation properties can only participate in a single relationship.
If you want to override an existing relationship call 'Ignore' on the navigation
'NxProperty.NxLog' first in 'OnModelCreating'.
我必须如何在OnModelCreating(ModelBuilder modelBuilder)
方法中建立关系?
你能与我分享 modelBuilder.Entity<NxProperty>().HasMany(...)
的代码吗?
提前致谢
我看了 9 遍才看懂你的代码。所以首先,在我看来,让相同的 class 代表多个表是错误的。如果你想一起处理它们,请为两者创建一个基础 class,然后创建子 classes。这就是为什么您无法正确映射它们的原因,因为名称不明确。但我是来帮忙的。
- 步骤:重构您的
NxProperty
class.
- 将 NxProperty 设为抽象 class。
- 创建一个空的 class,它继承自这个名为
NxRequestProperty
的 class。
- 创建另一个空的 class 继承自此 class,称为
NxResponseProperty
。
示例:
//NgProperty.cs
public abstract class NxProperty
{
public string NxPropertyId { get; set; }
public string NxWorkspaceId { get; set; }
public string NxConversationId { get; set; }
public string NxLogId { get; set; }
public NxLog NxLog { get; set; }
public JToken Value { get; set; }
}
// NxRequestProperty.cs
// using sealed is just my preference so other
// developers know not to inherit from it without
// asking questions, you can exclude it if you wish.
public sealed class NxRequestProperty : NxProperty {
}
// NxResponseProperty.cs
public sealed class NxResponseProperty : NxProperty {
}
- 步骤:重构您的
NxLog
class。使用具体的 classes 而不是 NxProperty
抽象的 class.
示例:
// NxLog.cs
public sealed class NxLog
{
public string NxLogId { get; set; }
public string NxWorkspaceId { get; set; }
public string NxConversationId { get; set; }
public NxConversation NxConversation { get; set; }
public List<NxOutputText> NxOutputTexts { get; set; }
public List<NxRequestProperty> RequestProperties { get; set; }
public List<NxResponseProperty> ResponseProperties { get; set; }
}
- 步骤:重构您的
CustomDbContext
。您 NxProperty
class 现在是抽象的,您不应该将其用作 DbSet
(恕我直言),让我们重构它。
示例:
// CustomDbContext.cs
public sealed class CustomDbContext : DbContext
{
DbSet<NxWorkspace> Workspaces { get; set; }
DbSet<NxConversation> Conversations { get; set; }
DbSet<NxLog> Logs { get; set; }
DbSet<NxOutputText> OutputTexts { get; set; }
// Refactor starts here!
DbSet<NxRequestProperty> RequestProperties { get; set; }
DbSet<NxResponseProperty> ResponseProperties { get; set; }
// Refactor ends here!
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<NxWorkspace>().HasKey(w => w.NxWorkspaceId);
modelBuilder.Entity<NxConversation>().HasKey(c => new { c.NxWorkspaceId, c.NxConversationId });
modelBuilder.Entity<NxLog>().HasKey(l => new { l.NxWorkspaceId, l.NxConversationId, l.NxLogId });
modelBuilder.Entity<NxOutputText>().HasKey(o => new { o.NxWorkspaceId, o.NxConversationId, o.NxLogId, o.NxOutputTextId });
// Refactor starts here!
modelBuilder.Entity<NxRequestProperty>().HasKey(p => new { p.NxWorkspaceId, p.NxConversationId, p.NxLogId, p.NxPropertyId });
modelBuilder.Entity<NxResponseProperty>().HasKey(p => new { p.NxWorkspaceId, p.NxConversationId, p.NxLogId, p.NxPropertyId });
modelBuilder.Entity<NxRequestProperty>().Property(l => l.Value)
.HasConversion<string>(
o => JsonConvert.SerializeObject(o),
d => JsonConvert.DeserializeObject<JToken>(d)
);
modelBuilder.Entity<NxResponseProperty>().Property(l => l.Value)
.HasConversion<string>(
o => JsonConvert.SerializeObject(o),
d => JsonConvert.DeserializeObject<JToken>(d)
);
// Refactor ends here!
//Other steps
}
}
- (和最后)步骤:我不确定 EF Core 现在是否可以映射关系,但我相信始终声明的源代码是更好的源代码,所以这里是映射它的方法。由于有组合键,你需要有外键作为所有组合键。
示例:
// CustomDbContext.cs -> inside the OnModelCreating method
modelBuilder.Entity<NxRequestProperty>
.HasOne(p => p.NxLog)
.WithMany(l => l.RequestProperties)
.HasForeignKey(l => new { l.NxWorkspaceId, l.NxConversationId, l.NxLogId });
modelBuilder.Entity<NxResponseProperty>
.HasOne(p => p.NxLog)
.WithMany(l => l.ResponseProperties)
.HasForeignKey(l => new { l.NxWorkspaceId, l.NxConversationId, l.NxLogId });
编辑:
看着我的回答,我意识到也许将 NxProperty
重构为接口更好(并将其称为 INxProperty
)。两者都可以,但我认为界面更适合这个。
我想使用 List
在 NxProperty
自定义 class 和 NxLog
自定义 class 之间建立双重关系。
public class NxLog
{
public string NxLogId { get; set; }
public string NxWorkspaceId { get; set; }
public string NxConversationId { get; set; }
public NxConversation NxConversation { get; set; }
public List<NxOutputText> NxOutputTexts { get; set; }
public List<NxProperty> RequestProperties { get; set; } //1st Relation
public List<NxProperty> ResponseProperties { get; set; } //2nd Relation
}
public class NxProperty
{
public string NxPropertyId { get; set; }
public string NxWorkspaceId { get; set; }
public string NxConversationId { get; set; }
public string NxLogId { get; set; }
public NxLog NxLog { get; set; }
public JToken Value { get; set; }
}
在DbContext
女儿class我有:
class CustomDbContext:DbContext
{
DbSet<NxWorkspace> Workspaces { get; set; }
DbSet<NxConversation> Conversations { get; set; }
DbSet<NxLog> Logs { get; set; }
DbSet<NxOutputText> OutputTexts { get; set; }
DbSet<NxProperty> RequestProperties { get; set; }
DbSet<NxProperty> ResponseProperties { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<NxWorkspace>().HasKey(w => w.NxWorkspaceId);
modelBuilder.Entity<NxConversation>().HasKey(c => new { c.NxWorkspaceId, c.NxConversationId });
modelBuilder.Entity<NxLog>().HasKey(l => new { l.NxWorkspaceId, l.NxConversationId, l.NxLogId });
modelBuilder.Entity<NxOutputText>().HasKey(o => new { o.NxWorkspaceId, o.NxConversationId, o.NxLogId, o.NxOutputTextId });
modelBuilder.Entity<NxProperty>().HasKey(p => new { p.NxWorkspaceId, p.NxConversationId, p.NxLogId, p.NxPropertyId });
modelBuilder.Entity<NxProperty>().Property(l => l.Value)
.HasConversion<string>(
o => JsonConvert.SerializeObject(o),
d => JsonConvert.DeserializeObject<JToken>(d)
);
//Other steps
}
}
但我得到了异常:
System.InvalidOperationException: Unable to determine the relationship represented by navigation 'NxLog.RequestProperties' of type 'List<NxProperty>'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidatePropertyMapping(IModel model, IDiagnosticsLogger`1 logger)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
at Microsoft.EntityFrameworkCore.SqlServer.Internal.SqlServerModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.ValidatingConvention.ProcessModelFinalized(IModel model)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalized(IModel model)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalized(IModel model)
at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel()
at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel()
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, ModelDependencies modelDependencies)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder, 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, 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.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 outputDir, String contextType, 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)
Unable to determine the relationship represented by navigation 'NxLog.RequestProperties' of type 'List<NxProperty>'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
PM>
我需要确保我有正确的代码。
我正在尝试
modelBuilder.Entity<NxLog>()
.HasMany(l => l.RequestProperties)
.WithOne(p => p.NxLog).HasForeignKey(p => p.NxLogId);
modelBuilder.Entity<NxLog>()
.HasMany(l => l.ResponseProperties)
.WithOne(p => p.NxLog).HasForeignKey(p => p.NxLogId);
但我明白了...
Cannot create a relationship between 'NxLog.ResponseProperties' and 'NxProperty.NxLog'
because a relationship already exists between 'NxLog.RequestProperties' and 'NxProperty.NxLog'.
Navigation properties can only participate in a single relationship.
If you want to override an existing relationship call 'Ignore' on the navigation
'NxProperty.NxLog' first in 'OnModelCreating'.
我必须如何在OnModelCreating(ModelBuilder modelBuilder)
方法中建立关系?
你能与我分享 modelBuilder.Entity<NxProperty>().HasMany(...)
的代码吗?
提前致谢
我看了 9 遍才看懂你的代码。所以首先,在我看来,让相同的 class 代表多个表是错误的。如果你想一起处理它们,请为两者创建一个基础 class,然后创建子 classes。这就是为什么您无法正确映射它们的原因,因为名称不明确。但我是来帮忙的。
- 步骤:重构您的
NxProperty
class.
- 将 NxProperty 设为抽象 class。
- 创建一个空的 class,它继承自这个名为
NxRequestProperty
的 class。 - 创建另一个空的 class 继承自此 class,称为
NxResponseProperty
。
示例:
//NgProperty.cs
public abstract class NxProperty
{
public string NxPropertyId { get; set; }
public string NxWorkspaceId { get; set; }
public string NxConversationId { get; set; }
public string NxLogId { get; set; }
public NxLog NxLog { get; set; }
public JToken Value { get; set; }
}
// NxRequestProperty.cs
// using sealed is just my preference so other
// developers know not to inherit from it without
// asking questions, you can exclude it if you wish.
public sealed class NxRequestProperty : NxProperty {
}
// NxResponseProperty.cs
public sealed class NxResponseProperty : NxProperty {
}
- 步骤:重构您的
NxLog
class。使用具体的 classes 而不是NxProperty
抽象的 class.
示例:
// NxLog.cs
public sealed class NxLog
{
public string NxLogId { get; set; }
public string NxWorkspaceId { get; set; }
public string NxConversationId { get; set; }
public NxConversation NxConversation { get; set; }
public List<NxOutputText> NxOutputTexts { get; set; }
public List<NxRequestProperty> RequestProperties { get; set; }
public List<NxResponseProperty> ResponseProperties { get; set; }
}
- 步骤:重构您的
CustomDbContext
。您NxProperty
class 现在是抽象的,您不应该将其用作DbSet
(恕我直言),让我们重构它。
示例:
// CustomDbContext.cs
public sealed class CustomDbContext : DbContext
{
DbSet<NxWorkspace> Workspaces { get; set; }
DbSet<NxConversation> Conversations { get; set; }
DbSet<NxLog> Logs { get; set; }
DbSet<NxOutputText> OutputTexts { get; set; }
// Refactor starts here!
DbSet<NxRequestProperty> RequestProperties { get; set; }
DbSet<NxResponseProperty> ResponseProperties { get; set; }
// Refactor ends here!
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<NxWorkspace>().HasKey(w => w.NxWorkspaceId);
modelBuilder.Entity<NxConversation>().HasKey(c => new { c.NxWorkspaceId, c.NxConversationId });
modelBuilder.Entity<NxLog>().HasKey(l => new { l.NxWorkspaceId, l.NxConversationId, l.NxLogId });
modelBuilder.Entity<NxOutputText>().HasKey(o => new { o.NxWorkspaceId, o.NxConversationId, o.NxLogId, o.NxOutputTextId });
// Refactor starts here!
modelBuilder.Entity<NxRequestProperty>().HasKey(p => new { p.NxWorkspaceId, p.NxConversationId, p.NxLogId, p.NxPropertyId });
modelBuilder.Entity<NxResponseProperty>().HasKey(p => new { p.NxWorkspaceId, p.NxConversationId, p.NxLogId, p.NxPropertyId });
modelBuilder.Entity<NxRequestProperty>().Property(l => l.Value)
.HasConversion<string>(
o => JsonConvert.SerializeObject(o),
d => JsonConvert.DeserializeObject<JToken>(d)
);
modelBuilder.Entity<NxResponseProperty>().Property(l => l.Value)
.HasConversion<string>(
o => JsonConvert.SerializeObject(o),
d => JsonConvert.DeserializeObject<JToken>(d)
);
// Refactor ends here!
//Other steps
}
}
- (和最后)步骤:我不确定 EF Core 现在是否可以映射关系,但我相信始终声明的源代码是更好的源代码,所以这里是映射它的方法。由于有组合键,你需要有外键作为所有组合键。
示例:
// CustomDbContext.cs -> inside the OnModelCreating method
modelBuilder.Entity<NxRequestProperty>
.HasOne(p => p.NxLog)
.WithMany(l => l.RequestProperties)
.HasForeignKey(l => new { l.NxWorkspaceId, l.NxConversationId, l.NxLogId });
modelBuilder.Entity<NxResponseProperty>
.HasOne(p => p.NxLog)
.WithMany(l => l.ResponseProperties)
.HasForeignKey(l => new { l.NxWorkspaceId, l.NxConversationId, l.NxLogId });
编辑:
看着我的回答,我意识到也许将 NxProperty
重构为接口更好(并将其称为 INxProperty
)。两者都可以,但我认为界面更适合这个。