简体   繁体   English

EF 3.1:序列不包含任何元素

[英]EF 3.1: Sequence contains no elements

I have a stored procedure GetVideo in a SQL Server 2019 database that does this:我在 SQL Server 2019 数据库中有一个存储过程GetVideo执行此操作:

select 
    [video.id] = vid,
    [video.title] = title
from 
    videos
for json path, root('x');

Which returns this JSON:返回这个 JSON:

{
    "x": 
    [
    {
        "video": 
        {
            "id": 11,
            "title": "Forest Gump"
        }
    }, 
    {
        "video": 
        {
            "id": 22,
            "title": "Merry Christmas"
        }
    }
    ]
}

However using C# and EF Core 3.1 generates an error:但是使用 C# 和 EF Core 3.1 会产生错误:

Sequence has no elements序列没有元素

public class Sp
{
    public List<video> XV {get; set;}

    public class video
    {
        public int id {get; set;}
        public string title {get; set;}
    }
}

public async Task<ActionResult<IEnumerable<Sp>>> X()  // Task<IActionResult> same error
{
    // this line throws "Sequence has no elements", same for .ToArrayAsync()
    var v = await _context.Sp.FromSqlRaw("dbo.GetVideo").ToListAsync(); 
    return Ok(a);
}

Update更新

  1. My DbContext class does have this line omitted in original question: public virtual DbSet<Sp> Sp { get; set; }.我的DbContext class 在原始问题中确实省略了这一行: public virtual DbSet<Sp> Sp { get; set; }. public virtual DbSet<Sp> Sp { get; set; }.

  2. .FromSqlRaw() always works for calling a stored procedure. .FromSqlRaw()始终适用于调用存储过程。 That is, it works without for json path, root('x') in stored procedure along with builder.Entity<SP>().HasNoKey() .也就是说,它在没有for json path, root('x')以及builder.Entity<SP>().HasNoKey()的情况下工作。

Unfortunately I'm locked in with JSON being returned from SQL Server and EF Core version 3.1.不幸的是,我被从 SQL 服务器和 EF Core 版本 3.1 返回的 JSON 锁定了。 At the moment I'm wondering if DbSet<Sp> is right because it may expects table-like returns therefore Sequence contains no elements?目前我想知道DbSet<Sp>是否正确,因为它可能期望类似表的返回,因此Sequence 不包含任何元素?

I need to find a way to call a stored procedure which returns JSON instead of table-like data.我需要找到一种方法来调用返回 JSON 而不是类似表的数据的存储过程。

I think you probably need to break your _context.FromSqlRaw() and ToListAsync() into two separate lines and make sure that the first one is not returning an empty list.我认为您可能需要将_context.FromSqlRaw()ToListAsync()分成两行,并确保第一行不返回空列表。 I'm not familiar with the FromSqlRaw , but "sequence contains no elements" is probably the result of trying to do something to an IEnumerable when the referenced collection is empty.我不熟悉FromSqlRaw ,但“序列不包含任何元素”可能是在引用的集合为空时尝试对 IEnumerable 执行某些操作的结果。

var v = await _context.Sp.FromSqlRaw("dbo.GetVideo");
if (v.Any()) return Ok(await v.ToListAsync());
return NotFound();

First of all, from what you shared it looks like class Video should be your entity class (note I'm calling it Video with a capital V because that is recommended in all coding guidelines).首先,从您分享的内容来看, class Video应该是您的实体 class(请注意,我将其称为带有大写VVideo ,因为所有编码指南都建议这样做)。

You did not share it with us, but please make sure you have this in your DB Context class:您没有与我们分享它,但请确保您的数据库上下文 class 中有这个:

public DbSet<Video> Videos { get; set; }

To make this easier, place class Video outside of the wrapper class SP , then maybe even remove class SP .为了使这更容易,将class Video放在包装器 class SP之外,然后甚至可以删除class SP

After that I see 2 options:之后我看到 2 个选项:

Option 1 : change the stored procedure选项 1 :更改存储过程

... to contain just SELECT vid AS id, title FROM videos . ...仅包含SELECT vid AS id, title FROM videos

That should return exactly the data that _context.Videos.FromSqlRaw() expects.这应该准确返回_context.Videos.FromSqlRaw()期望的数据。 Note: it definitely does not expect JSON. For more info, see Microsoft Learn: Using SQL queries with EF Core .注意:它绝对不期望 JSON。有关详细信息,请参阅Microsoft Learn:Using SQL queries with EF Core

The code to run the SP would become something like this:运行 SP 的代码会变成这样:

var list = await _context.Videos.FromSqlRaw("dbo.videos").ToListAsync();

Option 2 : drop the stored procedure, forget about writing SQL (my favourite option)选项 2 :删除存储过程,忘记写 SQL(我最喜欢的选项)

... and do just this: ...然后这样做:

var list = await _context.Videos.ToListAsync();

This is what normal EF Core code would and should do.这是正常的 EF Core 代码应该做的事情。 No stored procedures are needed.不需要存储过程。 Writing your own SQL is almost never needed, because EF Core will generate proper SQL for you on the fly.几乎不需要编写您自己的 SQL,因为 EF Core 会即时为您生成正确的 SQL。

One more thing: you will now run into the problem that the database table uses vid while class Video uses id .还有一件事:您现在会遇到数据库表使用vid而 class 视频使用id的问题。 The solution would be to change either vid to id (in the DB Table), or change id to vid (in the Video class).解决方案是将vid更改为id (在 DB 表中),或将id更改为vid (在 Video 类中)。

It is a ground rule of EF Core that property names of Entity classes match with column names in the database tables .实体类的属性名称数据库表中的列名称相匹配是 EF Core 的基本规则。 Maybe there are ways to make it work if they don't match, but I wouldn't know if there are, and it's just easiest and clearest if they are the same.如果它们不匹配,也许有办法让它工作,但我不知道是否有,如果它们相同,那将是最简单和最清楚的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM