You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否在Entity Framework Core的FromSql方法中使用Inner Join?

解决EF Core FromSql使用Inner Join时的重复列错误

嘿,这个问题我之前也踩过坑!你遇到的SqlException: The column 'Id' was specified multiple times for 'c'错误,根源很简单:你用了Select *查询,而Contacts和Phones表都有Id列,这导致查询结果里出现了两个同名的Id字段,EF Core没法把这种重复列映射到Contact实体上,自然就报错了。

下面给你几个可行的解决方案:

方案1:只查询目标实体的列

既然你最终要返回的是Contact实体,那完全没必要把Phones的列也查出来。修改你的SQL语句,只选择Contacts表的所有列就行:

return DbContext.Contacts.FromSql<Contact>(
    "Select c.* From Contacts c Inner Join Phones p on p.ContactId = c.Id Where c.Id <= 2 And p.PhoneNumber='01234567890'"
)
.Include(o => o.RegisteredByUser)
.AsNoTracking()
.ToListAsync();

这里用c.*代替*,只返回Contacts的列,就不会有重复的Id了。

方案2:用EF Core的Linq查询代替手动SQL

其实EF Core本身就支持关联查询,完全没必要手动写Inner Join。如果你的Contact实体已经定义了Phones导航属性(比如public ICollection<Phone> Phones { get; set; }),可以直接用Linq来实现需求:

return DbContext.Contacts
    .Where(c => c.Id <= 2 && c.Phones.Any(p => p.PhoneNumber == "01234567890"))
    .Include(o => o.RegisteredByUser)
    // 如果需要同时返回关联的Phone数据,加上下面这行
    // .Include(c => c.Phones)
    .AsNoTracking()
    .ToListAsync();

这种方式EF会自动帮你生成正确的Join语句,还能避免手动写SQL可能带来的错误,维护起来也更方便。

方案3:如果需要多表数据,用DTO接收

要是你确实需要同时获取Contacts和Phones的字段,那可以创建一个DTO类,包含所有需要的属性,并且给重复列起别名:
比如先定义DTO:

public class ContactPhoneDto
{
    public int ContactId { get; set; }
    public string ContactName { get; set; } // 假设Contact有这个属性
    public int PhoneId { get; set; }
    public string PhoneNumber { get; set; }
}

然后修改SQL语句,给列起别名匹配DTO:

return DbContext.Set<ContactPhoneDto>().FromSql(
    "Select c.Id as ContactId, c.Name as ContactName, p.Id as PhoneId, p.PhoneNumber From Contacts c Inner Join Phones p on p.ContactId = c.Id Where c.Id <= 2 And p.PhoneNumber='01234567890'"
)
.AsNoTracking()
.ToListAsync();

这样就能正确映射,不会出现重复列的问题了。

内容的提问来源于stack exchange,提问作者Jourmand

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:21:32