实体框架代码第一个一对多关系映射与链接表

Min*_*nie 4 code-first ef-code-first entity-framework-4.1

当两个表之间存在链接(连接)表时,我有一个关于两个表之间的一对多关系的问题.

示例表:

ChildTable:
ID int NOT NULL PK
Relation int NOT NULL

ParentTable:
ID int NOT NULL PK
Name nvarchar(50) NOT NULL

ParentChildren:
ParentTable_ID int NOT NULL PFK
ChildTable_ID int NOT NULL PFK
Run Code Online (Sandbox Code Playgroud)

实体:

public class ChildTable
{
    public ChildTable()
    {
        this.ParentTables = new List<ParentTable>();
    }

    public int ID { get; set; }       
    public int Relation { get; set; }
    public virtual ICollection<ParentTable> ParentTables { get; set; }
}

public class ParentTable
{
    public ParentTable()
    {
        this.ChildTables = new List<ChildTable>();
    }

    public int ID { get; set; }   
    public string Name { get; set; }
    public virtual ICollection<ChildTable> ChildTables { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

制图:

public class ChildTableMap : EntityTypeConfiguration<ChildTable>
{
    public ChildTableMap()
    {
        // Primary Key
        this.HasKey(t => t.ID);

        // Properties
        // Table & Column Mappings
        this.ToTable("ChildTable");
        this.Property(t => t.ID).HasColumnName("ID");
        this.Property(t => t.Relation).HasColumnName("Relation");
    }
}
public class ParentTableMap : EntityTypeConfiguration<ParentTable>
{
    public ParentTableMap()
    {
        // Primary Key
        this.HasKey(t => t.ID);

        // Properties
        this.Property(t => t.Name)
            .IsRequired()
            .HasMaxLength(50);

        // Table & Column Mappings
        this.ToTable("ParentTable");
        this.Property(t => t.ID).HasColumnName("ID");
        this.Property(t => t.Name).HasColumnName("Name");

        // Relationships
        this.HasMany(t => t.ChildTables)
            .WithMany(t => t.ParentTables)
            .Map(m =>
                {
                    m.ToTable("ParentChildren");
                    m.MapLeftKey("ParentTable_ID");
                    m.MapRightKey("ChildTable_ID");
                });

    }
}
Run Code Online (Sandbox Code Playgroud)

语境:

public class TestContext : DbContext
{
    static TestContext()
    { 
        Database.SetInitializer<TestContext>(null);
    }

    public DbSet<ChildTable> ChildTables { get; set; }
    public DbSet<ParentTable> ParentTables { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
        modelBuilder.Configurations.Add(new ChildTableMap());
        modelBuilder.Configurations.Add(new ParentTableMap());
    }
}
Run Code Online (Sandbox Code Playgroud)

添加子和父的代码:

using (var context = new TestContext())
        {
                var parent = new ParentTable { Name = "Mother Goose" };                   
                var child = new ChildTable { Relation = 1 };                   
                context.ParentTables.Add(parent);
                context.ChildTables.Add(child);
                parent.ChildTables.Add(child);
                context.SaveChanges();
        }
Run Code Online (Sandbox Code Playgroud)

一切都按预期工作,但我真的只有一个父母和很多孩子.

如何进行包括写入链接表的映射(更改后的ChildTable类没有使用ParentTable的ICollection)?

Sla*_*uma 7

无法定义这样的映射.连接表仅适用于多对多关系.您必须记住,您的数据库架构(您无法更改,正如您在问题的评论中所述)已经定义了多对多关系.例如这两个条目......

ParentTable_ID:  1    2
ChildTable_ID:   1    1
Run Code Online (Sandbox Code Playgroud)

...是表中的有效条目ParentChildren,它们不违反PK约束,并且他们说孩子1有两个父母1和2.

如果您的业务逻辑仅允许子级只有一个父级,则数据库架构的建模错误.你不能用EF解决这个缺陷.

一种可能的解决方法可能是在代码中的业务逻辑中确保实体的ParentTables集合ChildTable永远不会有多个元素,可能是通过引入一个未映射的帮助器属性:

public class ChildTable
{
    public ChildTable()
    {
        this.ParentTables = new List<ParentTable>();
    }

    public int ID { get; set; }       
    public int Relation { get; set; }
    public virtual ICollection<ParentTable> ParentTables { get; set; }

    [NotMapped] // or use .Ignore(c => c.ParentTable) in Fluent API
    public ParentTable ParentTable
    {
        get
        {
            return ParentTables.SingleOrDefault();
            // let is crash if there is more than one element in the list
        }

        set
        {
            var oldParent = ParentTables.SingleOrDefault();
            if (oldParent != value)
            {
                ParentTables.Clear();
                if (value != null)
                    ParentTables.Add(value);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您只使用该ParentTable物业,这只是一点帮助.您必须避免使用该集合并添加多个父级.你不能成功,private因为它必须被映射.在这段关系的另一边也不安全.你可以写:parent1.ChildTables.Add(child1); parent2.ChildTables.Add(child1);这将导致child1数据库中的两个父母.您可以通过编写辅助方法来捕获这一点,该方法用于在ParentTable实体上添加子项,以检查添加的子项是否还没有父项之外的this父项.