EF Core 2.0执行无主键返回存储过程的解决方案咨询
绕过EF Core 2.0存储过程必须返回主键的限制方法
老哥,你遇到的这个问题我之前在项目里也碰到过——EF Core 2.0默认确实会要求映射存储结果的实体有主键,毕竟它的变更追踪机制依赖主键来识别对象。不过有几种靠谱的方法能绕开这个限制,给你梳理一下:
方法1:用SqlQuery直接返回匿名类型或普通DTO
EF Core 2.0里可以直接调用context.Database.SqlQuery来执行存储过程,这种方式不需要把结果映射到EF托管的实体,自然也就没主键要求。你可以定义一个简单的DTO类(甚至用匿名类型)来接收结果:
// 先定义一个普通的DTO,不需要任何EF配置 public class ProcResultDto { public string ColumnA { get; set; } public int ColumnB { get; set; } } // 执行存储过程 var param = new SqlParameter("@InputParam", "test value"); var results = context.Database.SqlQuery<ProcResultDto>( "EXEC GetNonKeyedData @InputParam", param ).ToList();
这种方式的好处是简单直接,而且返回的对象不会被EF追踪,适合纯只读的查询场景。
方法2:配置无主键的实体
如果你确实需要把结果映射到EF的实体(比如后续要用到EF的一些扩展功能),可以手动标记这个实体没有主键。在你的DbContext的OnModelCreating方法里配置:
protected override void OnModelCreating(ModelBuilder modelBuilder) { // 标记实体无主键 modelBuilder.Entity<NonKeyedEntity>() .HasNoKey(); } // 对应的实体类,不需要主键属性 public class NonKeyedEntity { public string DataField1 { get; set; } public decimal DataField2 { get; set; } }
配置完成后,你就可以用FromSql来查询存储过程了:
var results = context.NonKeyedEntities.FromSql("EXEC YourStoredProc").ToList();
EF Core 2.0已经正式支持HasNoKey方法,不用担心兼容性问题。
方法3:临时主键(折中方案)
如果上面两种方法都不适合你的场景,还可以给实体加一个“假”的主键——比如随便选一个返回的字段(哪怕不是唯一的),或者甚至生成一个计算属性。不过要注意,这种方法下EF会把这个字段当作主键处理,可能会导致变更追踪的异常,所以只适合纯只读的场景:
public class TempEntity { // 用某个现有字段作为临时主键 public string SomeColumn { get; set; } public string OtherData { get; set; } } // 在OnModelCreating里配置主键 modelBuilder.Entity<TempEntity>() .HasKey(e => e.SomeColumn);
额外提醒
- 不管用哪种方法,只要是无主键或者临时主键的场景,返回的对象基本都是只读的,不要尝试对它们做修改后保存,EF的变更追踪会出问题。
- 如果后续升级到更高版本的EF Core,API可能会有调整,但核心思路还是一样的——要么绕开EF的实体追踪,要么明确告诉EF这个实体没有主键。
内容的提问来源于stack exchange,提问作者Ivan Pelly
相关产品推荐
相关产品推荐

