[英]EntityFramework error when deleting an entity with one-to-one optional relationship
[英]How to configure one-to-one optional relationship with EntityFramework?
那是我所擁有的最小測試用例。
public class Project
{
public int ProjectId { get; set; }
public string Name { get; set; }
}
public class Claim
{
[Key]
public int ClaimId { get; set; }
public int ProjectId { get; set; }
public virtual Project Project { get; set; }
public virtual CommentDiscussion Discussion { get; set; }
}
public class ForumThread
{
[Key]
public int ForumThreadId { get; set; }
public int ProjectId { get; set; }
public virtual Project Project { get; set; }
public virtual CommentDiscussion Discussion { get; set; }
}
public class CommentDiscussion
{
public int CommentDiscussionId { get; set; }
public int? ClaimId { get; set; }
public virtual Claim Claim { get; set; }
public int? ForumThreadId { get; set; }
public virtual ForumThread ForumThread { get; set; }
public int ProjectId { get; set; }
public virtual Project Project { get; set; }
}
modelBuilder.Entity<Claim>().HasRequired(c => c.CommentDiscussion).WithRequiredDependent(cd => cd.Claim);
modelBuilder.Entity<ForumThread>().HasRequired(c => c.CommentDiscussion).WithRequiredDependent(cd => cd.ForumThread);
我想配置以下關系: Claim
恰好具有一個CommentDiscussion
,而ForumThread
具有一個CommentDiscussion
。 CommentDiscussion
可以具有Claim
或ForumThread
。
如果將此創建為一次遷移,則一切正常。 但是,如果我分為兩個遷移,並且首先創建除CommentDiscussion
之外的所有CommentDiscussion
,則添加CommentDiscussion
遷移將生成:
AddForeignKey("dbo.ForumThreads", "ForumThreadId", "dbo.CommentDiscussions", "CommentDiscussionId");
AddForeignKey("dbo.Claims", "ClaimId", "dbo.CommentDiscussions", "CommentDiscussionId");
真的錯 即使我會手動解決遷移問題,EF也會錯誤地映射加載時的所有內容。
您需要注意兩件事。 您要存儲什么,什么是有效的。 並非所有可能的值都有效。
在這種情況下, CommentDiscussion
必須包含Claim
或ForumThread
引用,但不能同時設置兩者。
實體:
public class Claim
{
public int Id { get; set; }
public string Name { get; set; }
public CommentDiscussion CommentDiscussion { get; set; }
}
public class ForumThread
{
public int Id { get; set; }
public string Name { get; set; }
public CommentDiscussion CommentDiscussion { get; set; }
}
public class CommentDiscussion
{
public int Id { get; set; }
public int? ClaimId { get; set; }
public Claim Claim { get; set; }
public int? ForumThreadId { get; set; }
public ForumThread ForumThread { get; set; }
}
配置
public class ClaimConfiguration : EntityTypeConfiguration<Claim>
{
public ClaimConfiguration()
{
HasKey( e => e.Id );
Property( e => e.Name )
.IsRequired( )
.HasMaxLength( 100 );
}
}
public class ForumThreadConfiguration : EntityTypeConfiguration<ForumThread>
{
public ForumThreadConfiguration()
{
HasKey( e => e.Id );
Property( e => e.Name )
.IsRequired( )
.HasMaxLength( 100 );
}
}
public class CommentDiscussionConfiguration : EntityTypeConfiguration<CommentDiscussion>
{
public CommentDiscussionConfiguration()
{
HasKey( e => e.Id );
HasOptional( e => e.Claim )
.WithRequired( m => m.CommentDiscussion )
.Map( cfg => cfg.MapKey( nameof( CommentDiscussion.ClaimId ) ) );
HasOptional( e => e.ForumThread )
.WithRequired( m => m.CommentDiscussion )
.Map( cfg => cfg.MapKey( nameof( CommentDiscussion.ForumThreadId ) ) );
}
}
驗證以確保CommentDiscussion
具有對Claim
或ForumThread
一種引用:
public class ModelContext : DbContext
{
// Der Kontext wurde für die Verwendung einer ModelContext-Verbindungszeichenfolge aus der
// Konfigurationsdatei ('App.config' oder 'Web.config') der Anwendung konfiguriert. Diese Verbindungszeichenfolge hat standardmäßig die
// Datenbank 'ConsoleApp7.Model.ModelContext' auf der LocalDb-Instanz als Ziel.
//
// Wenn Sie eine andere Datenbank und/oder einen anderen Anbieter als Ziel verwenden möchten, ändern Sie die ModelContext-Zeichenfolge
// in der Anwendungskonfigurationsdatei.
public ModelContext()
: base( "name=ModelContext" )
{
}
protected override void OnModelCreating( DbModelBuilder modelBuilder )
{
modelBuilder.Configurations.Add( new ClaimConfiguration( ) );
modelBuilder.Configurations.Add( new ForumThreadConfiguration( ) );
modelBuilder.Configurations.Add( new CommentDiscussionConfiguration( ) );
base.OnModelCreating( modelBuilder );
}
protected override bool ShouldValidateEntity( DbEntityEntry entityEntry )
{
return base.ShouldValidateEntity( entityEntry );
}
protected override DbEntityValidationResult ValidateEntity( DbEntityEntry entityEntry, IDictionary<object, object> items )
{
if ( entityEntry.Entity is CommentDiscussion )
{
if ( !entityEntry.CurrentValues.GetValue<int?>( nameof( CommentDiscussion.ClaimId ) ).HasValue && !entityEntry.CurrentValues.GetValue<int?>( nameof( CommentDiscussion.ForumThreadId ) ).HasValue )
{
var list = new List<System.Data.Entity.Validation.DbValidationError>( );
list.Add( new System.Data.Entity.Validation.DbValidationError( nameof( CommentDiscussion.Claim ), "Claim or ForumThread is required" ) );
list.Add( new System.Data.Entity.Validation.DbValidationError( nameof( CommentDiscussion.ForumThread ), "Claim or ForumThread is required" ) );
return new System.Data.Entity.Validation.DbEntityValidationResult( entityEntry, list );
}
if ( entityEntry.CurrentValues.GetValue<int?>( nameof( CommentDiscussion.ClaimId ) ).HasValue && entityEntry.CurrentValues.GetValue<int?>( nameof( CommentDiscussion.ForumThreadId ) ).HasValue )
{
var list = new List<System.Data.Entity.Validation.DbValidationError>( );
list.Add( new System.Data.Entity.Validation.DbValidationError( nameof( CommentDiscussion.Claim ), "Only Claim or ForumThread is possible, not both" ) );
list.Add( new System.Data.Entity.Validation.DbValidationError( nameof( CommentDiscussion.ForumThread ), "Only Claim or ForumThread is possible, not both" ) );
return new System.Data.Entity.Validation.DbEntityValidationResult( entityEntry, list );
}
}
return base.ValidateEntity( entityEntry, items );
}
}
校驗
using ( var context = new ModelContext() )
{
CommentDiscussion discussion = new CommentDiscussion( );
context.Set<CommentDiscussion>( ).Add( discussion );
try
{
context.SaveChanges( );
}
catch ( Exception ex )
{
Console.WriteLine( ex.ToString() );
}
Claim claim = new Claim( );
ForumThread forumThread = new ForumThread( );
claim.CommentDiscussion = discussion;
forumThread.CommentDiscussion = discussion;
try
{
context.SaveChanges( );
}
catch ( Exception ex )
{
Console.WriteLine( ex.ToString( ) );
}
}
更新資料
這是模型生成的遷移
public partial class InitialCreate : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.Claims",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(nullable: false, maxLength: 100),
ClaimId = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.CommentDiscussions", t => t.ClaimId)
.Index(t => t.ClaimId);
CreateTable(
"dbo.CommentDiscussions",
c => new
{
Id = c.Int(nullable: false, identity: true),
ClaimId = c.Int(),
ForumThreadId = c.Int(),
})
.PrimaryKey(t => t.Id);
CreateTable(
"dbo.ForumThreads",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(nullable: false, maxLength: 100),
ForumThreadId = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.CommentDiscussions", t => t.ForumThreadId)
.Index(t => t.ForumThreadId);
}
public override void Down()
{
DropForeignKey("dbo.ForumThreads", "ForumThreadId", "dbo.CommentDiscussions");
DropForeignKey("dbo.Claims", "ClaimId", "dbo.CommentDiscussions");
DropIndex("dbo.ForumThreads", new[] { "ForumThreadId" });
DropIndex("dbo.Claims", new[] { "ClaimId" });
DropTable("dbo.ForumThreads");
DropTable("dbo.CommentDiscussions");
DropTable("dbo.Claims");
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.