能否在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
相关产品推荐
相关产品推荐

