在Entity Framework中通过Map实现INNER JOIN查询
在开发中,我们会遇到这样的场景:有时为了性能优化的需要,将一张表中的某个字段拆分至另外一张表中或者一个单独的数据库中。博客园博客文章表就是这样的情况,存储文章内容的字段被拆分至单独的数据库中。这样的拆分不应该影响业务逻辑层中实体类的设计,也就是说实体类应该感觉不到这个拆分。
在没有Entity Framework的日子里,我们通过手写带有INNER JOIN的SQL语句实现。
现在已经与Entity Framework朝朝暮暮,已经有点离不开她了,那该怎么办呢?
幸运的是,当初的选择没有错,Entity Framework性格温和,易于相处。通过modelBuilder.Entity<T>().Map(),可以指定实体类的属性映射至不同的数据库表中的字段,EF会自动生成带有INNER JOIN的SQL查询语句。这样拆分后,原来的LINQ查询代码不需要作任何修改。
——下面看代码示例——
实体类代码:
public class BlogPost
{
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
//拆分至单独数据库的文章内容字段
public string Body { get; set; }
}
Body属性对应于[CNBlogsText]数据库的[blog_PostBody]表中的[Text]字段。
其他属性对应于[CNBlogsData]数据库的[blog_Context]表中的字段。
如果不用Entity Framework,手写SQL查询语句:
SELECT bc.[ID], bc.Title,bc.[Description],bt.[Text] AS Body
FROM blog_Content bc
INNER JOIN CNBlogsText.dbo.blog_PostBody bt ON bc.ID = bt.ID
WHERE bc.[ID]=@ID
使用Entity Framework,LINQ查询语句如下(折分后与拆分前,LINQ查询语句是不变的):
using (BlogDbContext context = new BlogDbContext())
{
var result = from p in context.BlogPosts
where p.ID == entryId
select p;
return result.FirstOrDefault();
}
关键代码在BlogDbContext中:
public class BlogDbContext : DbContext
{
public DbSet<BlogPost> BlogPosts { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//映射至[CNBlogsData].[dbo].[blog_Content]表中的字段
modelBuilder.Entity<BlogPost>().Map(
bp =>
{
bp.Properties(
p => new
{
p.ID,
p.Title,
p.Description
});
bp.ToTable("blog_Content");
}
);
//映射至[CNBlogsText].[dbo].[blog_PostBody]表中的字段[Text]
modelBuilder.Entity<BlogPost>().Map(
bp =>
{
bp.Properties(p => new
{
p.Body
});
bp.ToTable("CNBlogsText_blog_PostBody");
}).Property(e => e.Body).HasColumnName("Text");
}
}
上面代码中的"CNBlogsText_blog_PostBody"是SQL Server中的同义词(SYNONYM),是为了实现Entity Framework的跨数据库查询,对应的是[CNBlogsText].[dbo].[blog_PostBody],详细请看真相大白:为什么Entity Framework不能进行跨数据库查询(附解决方法)(再次感谢killkill提供的解决方法)。
让我们来看一看Entity Framework生成的SQL语句:
exec sp_executesql N'SELECT TOP (1)
[Extent1].[ID] AS [ID],
[Extent2].[Title] AS [Title],
[Extent2].[Description] AS [Description],
[Extent1].[Text] AS [Text]
FROM [dbo].[CNBlogsText_blog_PostBody] AS [Extent1]
INNER JOIN [dbo].[blog_Content] AS [Extent2] ON [Extent1].[ID] = [Extent2].[ID]
WHERE [Extent1].[ID] = @p__linq__0',N'@p__linq__0 int',@p__linq__0=3560
干得不错吧!达到了我们想要的效果。
好了,又记录一次与Entity Framework相处的经历。
感言:有人说,相爱容易,相处难。但是与Entity Framework相处的日子,你对她的了解越多,你就越能感觉到她简单之中的不简单。