繁体   English   中英

如何使用EntityFramework配置一对一的可选关系?

[英]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可以具有ClaimForumThread

如果将此创建为一次迁移,则一切正常。 但是,如果我分为两个迁移,并且首先创建除CommentDiscussion之外的所有CommentDiscussion ,则添加CommentDiscussion迁移将生成:

  AddForeignKey("dbo.ForumThreads", "ForumThreadId", "dbo.CommentDiscussions", "CommentDiscussionId");
  AddForeignKey("dbo.Claims", "ClaimId", "dbo.CommentDiscussions", "CommentDiscussionId");

真的错 即使我会手动解决迁移问题,EF也会错误地映射加载时的所有内容。

您需要注意两件事。 您要存储什么,什么是有效的。 并非所有可能的值都有效。

在这种情况下, CommentDiscussion必须包含ClaimForumThread引用,但不能同时设置两者。

实体:

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具有对ClaimForumThread一种引用:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM