【问题标题】:Entity Framework Code First One-To-Many Relation Mapping with link table实体框架代码优先一对多关系映射与链接表
【发布时间】:2011-08-15 12:18:44
【问题描述】:

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

示例表:

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

实体:

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; }
}

映射:

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");
                });

    }
}

上下文:

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());
    }
}

添加孩子和父母的代码:

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();
        }

一切都按预期工作,但我真的只有一位父母和许多孩子。

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

【问题讨论】:

  • 你有这个现有的表结构并且不能改变它吗?我想知道,因为对于一对多的关系,您通常可以删除连接表并在 ChildTable 中引入一个 FK 列。我猜你不能因为某种原因改变你的桌子,对吧?
  • 是的,没有那个链接表会很容易,但不幸的是,这个链接表不能更改。

标签: entity-framework-4.1 ef-code-first code-first


【解决方案1】:

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

ParentTable_ID:  1    2
ChildTable_ID:   1    1

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

如果您的业务逻辑只允许子级只能有一个父级,则数据库模式的建模错误。您无法使用 EF 修复此缺陷。

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

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);
            }
        }
    }
}

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

【讨论】:

  • 感谢您的回答,对不起,我无法为答案投票,我没有足够的积分。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多