Con*_*ver 6 c# sql-server .net-core-3.0 ef-core-3.0
我正在使用 EF Core 3.0 将数据从 SQL Server 存储过程获取到名为 的对象模型中Recipient。该Recipient模型定义了几个属性EnvelopeId和Name,这些属性不是从存储过程返回的。当我使用 调用存储过程时FromSqlInterpolated,收到错误消息
“FromSql”操作的结果中不存在所需的列“EnvelopeId1”
根据我在 EF Core 文档中读到的内容,我应该能够向[NotMapped]这些属性添加属性,并且 EF Core 应该能够在读取或写入数据库时忽略它们,对吗?不幸的是,这对我不起作用,我收到了上述错误。
如果我在存储过程中添加两列并删除[NotMapped]对象模型中的属性,则一切正常。这证明我的其他列/属性名称匹配正确并且没有任何拼写错误。
我已经看到使用DbQuery而不是 的建议DbSet,但它已被弃用,所以我不想使用它。我看到过使用两种不同对象模型的建议,其中一种的属性与存储过程结果集完全匹配,但这只会导致大量额外的模型。我在这里做错了什么?
我的对象模型:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MyNamespace.Models
{
public class Recipient
{
[Key]
public long RecipientId { get; set; }
[NotMapped]
public Guid? EnvelopeId { get; set; }
public string Type { get; set; }
public string UserId { get; set; }
public string Email { get; set; }
[NotMapped]
public string Name { get; set; }
public string RoleName { get; set; }
public int RoutingOrder { get; set; }
public string Status { get; set; }
public DateTime StatusDate { get; set; }
public Recipient() { }
}
}
Run Code Online (Sandbox Code Playgroud)
我的数据库上下文:
using Microsoft.EntityFrameworkCore;
using MyNamespace.Models;
namespace MyNamespace.Data
{
public class MyDbContext : DbContext
{
public virtual DbSet<Recipient> Recipient { get; set; }
public virtual DbSet<Envelope> Envelope { get; set; }
public virtual DbSet<Template> Template { get; set; }
public MyDbContext (DbContextOptions<MyDbContext> options) : base(options)
{ }
}
}
Run Code Online (Sandbox Code Playgroud)
我的失败代码:
FormattableString sql = $"EXEC dbo.MyStoredProcedure @Param1={param1}, @Param2={param2}";
var result = await MyDbContext.Recipient.FromSqlInterpolated(sql).ToListAsync();
Run Code Online (Sandbox Code Playgroud)
编辑 #1 ...
对象Envelope模型:
public class Envelope
{
[Key]
public Guid EnvelopeId { get; set; }
public string Status { get; set; }
public DateTime StatusDate { get; set; }
public DateTime StatusPollDate { get; set; }
[NotMapped]
public List<Recipient> Recipients { get; set; }
public Envelope() {
Recipients = new List<Recipient>();
StatusPollDate = DateTime.Parse("1753-01-01");
}
}
Run Code Online (Sandbox Code Playgroud)
存储过程结果集架构:
[RecipientId] bigint,
[Type] varchar(20),
[UserId] varchar(50),
[Email] varchar(100),
[RoleName] varchar(100),
[RoutingOrder] int,
[Status] varchar(13),
[StatusDate] datetime
Run Code Online (Sandbox Code Playgroud)
在阅读了一些答案和评论后,我意识到 EF 正在创建影子属性,因为它识别出它Recipient是对象的子对象Envelope。老实说,我确实应该EnvelopeId在结果集中包含(并删除[NotMapped])以安抚 EF Core。我没有EnvelopeId在存储过程的结果集中返回的唯一原因是因为我首先将其作为输入参数传递,并且认为传递某些内容然后在每个结果中返回它会浪费网络资源创下纪录。
现在我不知道EnvelopeId1来自哪里,但这就是错误消息提到的内容。正如您在我的对象模型和存储过程结果集架构中看到的,我只引用了EnvelopeId. 我最好的猜测是,当 EF Core 决定创建影子属性时,它无法使用,EnvelopeId因为我的对象模型中已经有了它,因此它创建了一个名为的属性EnvelopeId1,然后期望它出现在存储过程的结果集中。
出现此错误消息的原因有两个:
“FromSql”操作的结果中不存在所需的列“EnvelopeId1”
显而易见的是,对于 SQL 结果集中的每一列,您尝试水合的对象图中必须有一个相应的属性,在这种情况下,您的Recipient类没有EnvelopeId1.
由于您的查询是一个存储过程,因此明智的做法是在此类问题中发布 SQL 结果,因为它将显示您尝试映射到对象图的 SQL 结构。
出现在 SQL 表中但不在对象图中的原因EnvelopeId1是实体框架为您尚未定义属性的外部对象创建了影子属性。
您尚未列出架构,Envelope但我的钱显示您拥有同等的ICollection<Recipient>财产。
创建NotMapped属性EnvelopeId只会使该架构更加混乱,我们应该正确映射它,或者您应该从存储过程输出中忽略它。
如果您打算
FromSql在 EF(.Net 或 Core)中使用变体,那么您应该始终在架构类中定义导航属性,因为数据库中的Shadow或Auto外键列会导致麻烦,除非您显式省略数据库中存在的列但不在你的架构中这意味着
SELECT *您必须显式定义所有列。
解决方案 1:修改存储过程
您可以简单地修改存储过程,使其不EvelopeId1从收件人表返回。
解决方案 2:为数据类中所有关系的两端完全定义属性
这里我使用了EnvelopeId1名称,这样就不需要迁移,但是我建议您将其更改为EnvelopeId,我个人使用数据库中存在的任何字段以数字结尾,表明我的一些关系没有得到充分定义。
public class Recipient
{
[Key]
public long RecipientId { get; set; }
public Guid? EnvelopeId1 { get; set; }
[ForeignKey(nameof(EnvelopeId1))]
public virtual Envelope Envelope { get; set; }
public string Type { get; set; }
public string UserId { get; set; }
public string Email { get; set; }
[NotMapped]
public string Name { get; set; }
public string RoleName { get; set; }
public int RoutingOrder { get; set; }
public string Status { get; set; }
public DateTime StatusDate { get; set; }
public Recipient() { }
}
Run Code Online (Sandbox Code Playgroud)
这是基于这样的假设:您的 Envelope 类具有与此部分定义类似的定义:
public class Envelope
{
[Key]
public Guid EnvelopeId { get; set; }
public virtual ICollection<Recipient> Recipients { get; set; } = new Hashset<Recipient>();
...
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10511 次 |
| 最近记录: |