实体框架中引用多个表的相同列外键

时间:2017-11-22 15:51:25

标签: c# entity-framework foreign-keys

我有两个班级

public class TypeA
{
    public Guid Id { get; set; }
    public List<Comment> Comments { get; set; }
}
public class TypeB
{
    public Guid Id { get; set; }
    public List<Comment> Comments { get; set; }
}

然后有

public class Comment
{
    public Guid Id { get; set; }
    public Guid ParentId { get; set; } //foreign key either to TypeA or TypeB
    public int Type { get; set; } //shows which class is referenced by foreign key ParentId
}

Comment具有TypeATypeB的外键。并且有属性Type,它告诉引用哪个外键。

现在我做了

_context.Set<TypeA>().Include(x => x.Comments).First(x => x.Id == Id)

但是是否可以限制Include语句或编写一个查询来检查Type属性以获取适当的外键引用,例如

_context.Set<TypeA>().Include(x => x.Comments.Where(c=>c.Type == 1)).First(x => x.Id == Id)

我想可以在查询中对Comment进行分组时完成,但TypeATypeB包含多个属性,我希望避免在new个关键字中写入select语句分配所有属性。

编辑:

我对现在拥有的东西非常满意。我这样做是为了理智,以防TypeATypeB id属性相同(99.9999999它不会)。

1 个答案:

答案 0 :(得分:0)

如果您已正确设置实体映射,则无需在Include语句中过滤某些内容。

public class TypeA
{
    public Guid Id { get; set; } = Guid.NewGuid();
    public virtual ICollection<Comment> Comments { get; set; } = new List<Comment>();
    public Comment AddComment(string text)
    {
        var comment = new Comment { Id = Guid.NewGuid(), ParentId = Id, Type = Types.TypeA, Text = text };
        Comments.Add(comment);
        return comment;
    }
}

public class TypeB
{
    public Guid Id { get; set; } = Guid.NewGuid();
    public virtual ICollection<Comment> Comments { get; set; } = new List<Comment>();
    public Comment AddComment(string text)
    {
        var comment = new Comment { Id = Guid.NewGuid(), ParentId = Id, Type = Types.TypeB, Text = text };
        Comments.Add(comment);
        return comment;
    }
}

public enum Types
{
    TypeA = 0,
    TypeB = 1
}

public class Comment
{
    public Guid Id { get; set; }
    public Guid ParentId { get; set; }
    public Types Type { get; set; }
    public string Text { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<TypeA> TypeAs { get; set; }
    public DbSet<TypeB> TypeBs { get; set; }

    public MyContext() : base("Name=MyContext") { }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

        modelBuilder.Entity<TypeA>()
            .HasKey(e => e.Id)
            .HasMany(e => e.Comments).WithMany();

        modelBuilder.Entity<TypeB>()
            .HasKey(e => e.Id)
            .HasMany(e => e.Comments).WithMany();
    }
}
internal sealed class Configuration : DbMigrationsConfiguration<MyContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = true;
    }
}

void Main()
{   
    // helper code to use migrations, just for demo purposes
    var migrator = new DbMigrator(new Configuration());
    migrator.Update();
    //

    var db = new MyContext();
    var a = new TypeA { Id = Guid.NewGuid() };
    db.TypeAs.Add(a);

    var b = new TypeB { Id = Guid.NewGuid() };
    db.TypeBs.Add(b);

    db.SaveChanges();

    a.AddComment("A1 ");
    a.AddComment("A2");

    b.AddComment("B1");
    b.AddComment("B2");
    b.AddComment("B3");

    db.SaveChanges();

    var dba = db.TypeAs.Include(x => x.Comments).First(e => e.Id == a.Id);
    foreach (var c in dba.Comments)
    {
        Console.WriteLine("{0} {1} {2} {3}", c.Text, c.Id, c.ParentId, c.Type.ToString());
    }
}

唯一的缺点是会涉及其他链接表(TypeAComment,TypeBComment)。