在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相处的日子,你对她的了解越多,你就越能感觉到她简单之中的不简单。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
2009-04-04 团队的沟通效率
2007-04-04 继续关于DiscuzNT及基于.NET的论坛软件的选择
2005-04-04 [SharePoint]更改活动目录(AD)中用户名的问题
2004-04-04 让大家久等了:终于完成了AOP尝鲜系列之第三部[JGTM'2004 [MVP]文章转载]