EntityFramework 正在尝试获取不存在的列
EntityFramework is trying to fetch non-existing column
EntityFramework 正在尝试获取不存在的列并且外键属性没有帮助。
在我的例子中,我有两个单对多关系表ps:
T_Blog
- Id
- FeaturedPost
T_Post
- Id
- BlogId
并且我定义了实体数据模型
public class T_Blog
{
[Key]
public int Id {get;set;}
public int? FeaturedPostId {get;set;}
[ForeignKey("FeaturedPostId")]
public virtual T_Post FeaturedPost {get;set;}
public virtual ICollection<T_Post> Posts {get;set;}
}
public class T_Post
{
[Key]
public int Id {get;set;}
[Required]
public int BlogId {get;set;}
[ForeignKey("BlogId")]
public T_Blog Blog {get;set;}
}
并且定义了这个元数据,每次我尝试执行 db.T_Post.Where(...).ToList();
时,EF 都会尝试获取 T_Blog_Id
列
我知道只要我的 T_Blog 有两个对 T_Post 的引用,EF 就会尝试获取这两个 ID。
ps:是的,我知道这种类型的数据模型不是最优的,但在我的情况下需要这种类型的非规范化(至少到目前为止)。
如何正确定义第二个关系以便 EF 知道要获取什么?
在我研究了一个小时之后,我找到了答案。如果 EF 无法定义映射,您不仅应该定义 ForeignKey
,还应该定义 InverseProperty
public class T_Blog
{
[Key]
public int Id {get;set;}
public int? FeaturedPostId {get;set;}
[ForeignKey("FeaturedPostId")]
public virtual T_Post FeaturedPost {get;set;}
[InverseProperty("Blog")]
public virtual ICollection<T_Post> Posts {get;set;}
}
找到here
您应该使用 FluentAPI 而不是注释来避免这种映射失败。
这是您的模型示例
public class BlogContext : DbContext
{
public BlogContext()
: base( "name=BlogContext" )
{
}
protected override void OnModelCreating( DbModelBuilder modelBuilder )
{
base.OnModelCreating( modelBuilder );
var blog = modelBuilder.Entity<T_Blog>();
blog.HasKey( e => e.Id );
blog.HasOptional( e => e.FeaturedPost )
.WithMany()
.HasForeignKey( e => e.FeaturedPostId )
.WillCascadeOnDelete( false );
var post = modelBuilder.Entity<T_Post>();
post.HasKey( e => e.Id );
post.HasRequired( e => e.Blog )
.WithMany( e => e.Posts )
.HasForeignKey( e => e.BlogId )
.WillCascadeOnDelete( true );
}
public virtual DbSet<T_Blog> Blogs { get; set; }
public virtual DbSet<T_Post> Posts { get; set; }
}
public class T_Blog
{
public int Id { get; set; }
public virtual ICollection<T_Post> Posts { get; set; }
public int? FeaturedPostId { get; set; }
public virtual T_Post FeaturedPost { get; set; }
}
public class T_Post
{
public int Id { get; set; }
public int? BlogId { get; set; }
public virtual T_Blog Blog { get; set; }
}
和自动生成的迁移
public partial class InitialCreate : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.T_Blog",
c => new
{
Id = c.Int(nullable: false, identity: true),
FeaturedPostId = c.Int(),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.T_Post", t => t.FeaturedPostId)
.Index(t => t.FeaturedPostId);
CreateTable(
"dbo.T_Post",
c => new
{
Id = c.Int(nullable: false, identity: true),
BlogId = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.T_Blog", t => t.BlogId, cascadeDelete: true)
.Index(t => t.BlogId);
}
public override void Down()
{
DropForeignKey("dbo.T_Blog", "FeaturedPostId", "dbo.T_Post");
DropForeignKey("dbo.T_Post", "BlogId", "dbo.T_Blog");
DropIndex("dbo.T_Post", new[] { "BlogId" });
DropIndex("dbo.T_Blog", new[] { "FeaturedPostId" });
DropTable("dbo.T_Post");
DropTable("dbo.T_Blog");
}
}
EntityFramework 正在尝试获取不存在的列并且外键属性没有帮助。
在我的例子中,我有两个单对多关系表ps:
T_Blog
- Id
- FeaturedPost
T_Post
- Id
- BlogId
并且我定义了实体数据模型
public class T_Blog
{
[Key]
public int Id {get;set;}
public int? FeaturedPostId {get;set;}
[ForeignKey("FeaturedPostId")]
public virtual T_Post FeaturedPost {get;set;}
public virtual ICollection<T_Post> Posts {get;set;}
}
public class T_Post
{
[Key]
public int Id {get;set;}
[Required]
public int BlogId {get;set;}
[ForeignKey("BlogId")]
public T_Blog Blog {get;set;}
}
并且定义了这个元数据,每次我尝试执行 db.T_Post.Where(...).ToList();
时,EF 都会尝试获取T_Blog_Id
列
我知道只要我的 T_Blog 有两个对 T_Post 的引用,EF 就会尝试获取这两个 ID。
ps:是的,我知道这种类型的数据模型不是最优的,但在我的情况下需要这种类型的非规范化(至少到目前为止)。
如何正确定义第二个关系以便 EF 知道要获取什么?
在我研究了一个小时之后,我找到了答案。如果 EF 无法定义映射,您不仅应该定义 ForeignKey
,还应该定义 InverseProperty
public class T_Blog
{
[Key]
public int Id {get;set;}
public int? FeaturedPostId {get;set;}
[ForeignKey("FeaturedPostId")]
public virtual T_Post FeaturedPost {get;set;}
[InverseProperty("Blog")]
public virtual ICollection<T_Post> Posts {get;set;}
}
找到here
您应该使用 FluentAPI 而不是注释来避免这种映射失败。
这是您的模型示例
public class BlogContext : DbContext
{
public BlogContext()
: base( "name=BlogContext" )
{
}
protected override void OnModelCreating( DbModelBuilder modelBuilder )
{
base.OnModelCreating( modelBuilder );
var blog = modelBuilder.Entity<T_Blog>();
blog.HasKey( e => e.Id );
blog.HasOptional( e => e.FeaturedPost )
.WithMany()
.HasForeignKey( e => e.FeaturedPostId )
.WillCascadeOnDelete( false );
var post = modelBuilder.Entity<T_Post>();
post.HasKey( e => e.Id );
post.HasRequired( e => e.Blog )
.WithMany( e => e.Posts )
.HasForeignKey( e => e.BlogId )
.WillCascadeOnDelete( true );
}
public virtual DbSet<T_Blog> Blogs { get; set; }
public virtual DbSet<T_Post> Posts { get; set; }
}
public class T_Blog
{
public int Id { get; set; }
public virtual ICollection<T_Post> Posts { get; set; }
public int? FeaturedPostId { get; set; }
public virtual T_Post FeaturedPost { get; set; }
}
public class T_Post
{
public int Id { get; set; }
public int? BlogId { get; set; }
public virtual T_Blog Blog { get; set; }
}
和自动生成的迁移
public partial class InitialCreate : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.T_Blog",
c => new
{
Id = c.Int(nullable: false, identity: true),
FeaturedPostId = c.Int(),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.T_Post", t => t.FeaturedPostId)
.Index(t => t.FeaturedPostId);
CreateTable(
"dbo.T_Post",
c => new
{
Id = c.Int(nullable: false, identity: true),
BlogId = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.T_Blog", t => t.BlogId, cascadeDelete: true)
.Index(t => t.BlogId);
}
public override void Down()
{
DropForeignKey("dbo.T_Blog", "FeaturedPostId", "dbo.T_Post");
DropForeignKey("dbo.T_Post", "BlogId", "dbo.T_Blog");
DropIndex("dbo.T_Post", new[] { "BlogId" });
DropIndex("dbo.T_Blog", new[] { "FeaturedPostId" });
DropTable("dbo.T_Post");
DropTable("dbo.T_Blog");
}
}