【问题标题】:How to refer two tables, using a column in another table - Entity Framework如何使用另一个表中的列来引用两个表 - 实体框架
【发布时间】:2018-09-19 08:45:38
【问题描述】:

根据上图,我有一个要求,表 C 需要同时引用表 A 和表 B。

注意:Table_C 中的RefId 是表A 和B 的引用键。

请参考代码sn-ps,

Table_A 类

public partial class Table_A
{
   public int Id { get; set; }
   public string Name { get; set; }
   public virtual ICollection<Table_C> Table_C { get; set; }
}

Table_B 类

public partial class Table_B
{
   public int Id { get; set; }
   public string Name { get; set; }
   public virtual ICollection<Table_C> Table_C { get; set; }
}

Table_C 类

public partial class Table_C
{
   public int Id { get; set; }
   public int RefId { get; set; }
   public Type Type {get; set; }
   public virtual Table_A Table_A { get; set; }
   public virtual Table_B Table_B { get; set; }
}

Fluent API

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Table_1>()
        .Property(e => e.Name)
        .IsFixedLength();

    modelBuilder.Entity<Table_1>()
        .HasMany(e => e.Table_3)
        .WithRequired(e => e.Table_1)
        .HasForeignKey(e => e.RefId)
        .WillCascadeOnDelete(false);

    modelBuilder.Entity<Table_2>()
        .Property(e => e.Name)
        .IsFixedLength();

    modelBuilder.Entity<Table_2>()
        .HasMany(e => e.Table_3)
        .WithRequired(e => e.Table_2)
        .HasForeignKey(e => e.RefId)
        .WillCascadeOnDelete(false);
}

但是,当尝试使用上面显示的代码实现此要求时,会出现以下错误。

INSERT 语句与 FOREIGN KEY 约束冲突 “FK_dbo.TableC.TableA_Id”。数据库“TestDB”中发生冲突, 表“dbo.TableA”,列“Id”。声明已终止

如何使用 Entity Framework 6(SQL Server 2014,.NET framework 4.6.1)来实现?

【问题讨论】:

    标签: asp.net .net sql-server entity-framework entity-framework-6


    【解决方案1】:

    对我来说似乎工作正常:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data;
    using System.Data.Entity;
    using System.IO;
    using System.IO.Compression;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Ef6Test
    {
    
        public partial class Table_A
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public virtual ICollection<Table_C> Table_C { get; } = new HashSet<Table_C>();
        }
        //Table_B Class
        public partial class Table_B
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public virtual ICollection<Table_C> Table_C { get; } = new HashSet<Table_C>();
        }
        //Table_C Class
        public partial class Table_C
        {
            public int Id { get; set; }
            public int RefId { get; set; }
            public string Type { get; set; }
    
            public virtual Table_A Table_A { get; set; }
    
            public virtual Table_B Table_B { get; set; }
        }
    
        class Db: DbContext
        {
            public DbSet<Table_A> Table_A { get; set; }
            public DbSet<Table_B> Table_B { get; set; }
            public DbSet<Table_C> Table_C { get; set; }
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
    
    
                modelBuilder.Entity<Table_A>()
                    .HasMany(e => e.Table_C)
                    .WithRequired(e => e.Table_A)
                    .HasForeignKey(e => e.RefId)
                    .WillCascadeOnDelete(false);
    
                modelBuilder.Entity<Table_B>()
                    .HasMany(e => e.Table_C)
                    .WithRequired(e => e.Table_B)
                    .HasForeignKey(e => e.RefId)
                    .WillCascadeOnDelete(false);
            }
        }
    
    
        class Program
        {
            static void Main(string[] args)
            {
    
                Database.SetInitializer(new DropCreateDatabaseAlways<Db>());
    
                using (var db = new Db())
                {
                    db.Database.Log = m => Console.WriteLine(m);
                    db.Database.Initialize(true);
    
                    var a = new Table_A();
                    var b = new Table_B();
                    var c = new Table_C();
    
                    a.Table_C.Add(c);
                    b.Table_C.Add(c);
    
                    db.Table_A.Add(a);
                    db.Table_B.Add(b);
                    db.Table_C.Add(c);
    
                    db.SaveChanges();
                }
                Console.ReadKey();
    
            }
        }
    }
    

    【讨论】:

    • 之所以有效,是因为 Table_A 和 Table_B 中的主键值相同。但是,如果尝试在 table_C 中引用 RefId 有两个不同的主键值,则会引发以下异常 SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.Table_C_dbo.Table_A_RefId". The conflict occurred in database "ManyF.Db", table "dbo.Table_A", column 'Id'.
    • 该模型显然要求Table_A和Table_B中的PK值相同。如果您希望 Table_C 实体使用不同的 PK 值,则需要两个 单独的 FK 属性。
    • 我们不能使用复合键或任何其他技术来完成此要求。可以说我不仅要引用两个表,而且还要引用更多,然后我必须为每个表使用单独的列
    • 当然你必须使用多个列来引用多个相关的表。有什么替代方案?
    【解决方案2】:

    我使用@David Browne - Microsoft 制作的cmets 设法满足了这个要求。因此,使用多个列来引用多个相关表是这种场景的方法。希望这将帮助任何寻找这种性质问题的答案的人。感谢@David Browne - Microsoft 的宝贵意见。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-27
      相关资源
      最近更新 更多