我有以下两个类:
public class Blog
{
public int Id { get; set; }
public BlogDetail BlogDetail { get; set; }
}
public class BlogDetail
{
public int Id { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
Blog和BlogDetail之间存在一对一的关系,外键是Blog.Id到BlogDetail.BlogId。
BlogDetail.BlogId是强制执行一对一关系的唯一约束。
BlogDetail.Id列是必需的,因为另一个表将BlogDetail称为一对多。
我添加了以下映射:
public BlogMap()
{
HasKey(t => t.Id);
Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
public BlogDetailMap()
{
HasKey(t => t.Id);
Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasRequired(t => t.Blog).WithMany().HasForeignKey(e => e.BlogId);
}
我试图让EF 6生成正确的sql查询,使用无主键字段作为无效的关键。它给了我以下sql查询:
select *
from Blog
left join BlogDetail on Blog.BlogDetail_Id = BlogDetail.Id
实际上我需要的是:
select *
from Blog
left join BlogDetail on Blog.Id = BlogDetail.BlogId
有人知道如何使用EF中的非主键字段实现一对一映射吗?我已经尽了一切可能无济于事。
如果有帮助,我会在BlogDetail上悬挂另一张桌子:
public class BlogDetailSupplier
{
public int Id { get; set; }
public int BlogDetailId { get; set; }
public BlogDetail BlogDetail { get; set; }
}
这就是为什么BlodDetail必须有一个ID PK列和一个briefId FK列。标准化。
答案 0 :(得分:0)
如果我理解正确,这就是你想要的:
public BlogMap()
{
HasOptional(b => b.BlogDetail).WithOptionalPrincipal(bd => bd.Blog);
}
这样BlogDetail
将拥有一个BlogId
外键,同时保持它自己的(身份)Id字段,您可以在一对多关系中使用它。
更新1
使用以下模型创建了一个新项目,通过应用上述映射,我能够实现您在问题中提出的要求:
public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public BlogDetail BlogDetail { get; set; }
}
public class BlogDetail
{
public int Id { get; set; }
public int PostCount { get; set; }
public Blog Blog { get; set; }
}
public class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<BlogDetail> BlogDetails { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>().HasOptional(b => b.BlogDetail).WithOptionalPrincipal(bd => bd.Blog);
}
}
public class ContextInitializer : DropCreateDatabaseIfModelChanges<MyContext>
{
protected override void Seed(MyContext db)
{
var blog1 = new Blog { Name = "Blog 1", BlogDetail = new BlogDetail { PostCount = 10 } };
var blog2 = new Blog { Name = "Blog 2", BlogDetail = new BlogDetail { PostCount = 28 } };
db.Blogs.AddRange(new List<Blog> { blog1, blog2 });
}
}
您可以在此处查看查询及其结果:
以下是表格:
答案 1 :(得分:0)
如果你在对象上
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity()entity.HasOne().WithOne().HasForeignKey(x=>x.BlogId); }
非常重要!! 查询时,_context.Blog.Include(inc=>inc.BlogDetail)
不要忘记 INCLUDE 否则对象将为空!!
答案 2 :(得分:-1)
使用这些地图:
public BlogMap()
{
HasKey(t => t.Id);
}
public BlogDetailMap()
{
HasKey(t => t.Id);
HasRequired(t => t.Blog)
.WithMany()
.HasForeignKey(x => x.BlogId)
.WillCascadeOnDelete(false);
}
这几乎产生了你的结果:
MyContext.BlogDetails.Includes(x => x.Blogs);
选择在BlogDetails上,并使用您之后的ID来加入博客。
SELECT
[Extent1].[id] AS [id],
[Extent1].[title] AS [title],
[Extent1].[BlogId] AS [BlogId],
[Extent2].[id] AS [id1],
[Extent2].[title] AS [title1],
[Extent2].[BlogDetail_id] AS [BlogDetail_id]
FROM [dbo].[BlogDetails] AS [Extent1]
INNER JOIN [dbo].[Blogs] AS [Extent2] ON [Extent1].[BlogId] = [Extent2].[id]