Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 引用ITVF会引发“在上一个操作完成之前在此上下文上启动的第二个操作”异常_C#_Linq_Asp.net Core_Asp.net Core 2.1_Entity Framework Core 2.1 - Fatal编程技术网

C# 引用ITVF会引发“在上一个操作完成之前在此上下文上启动的第二个操作”异常

C# 引用ITVF会引发“在上一个操作完成之前在此上下文上启动的第二个操作”异常,c#,linq,asp.net-core,asp.net-core-2.1,entity-framework-core-2.1,C#,Linq,Asp.net Core,Asp.net Core 2.1,Entity Framework Core 2.1,我试图在Linq查询中引用内联表值函数ITVF: var results = await ( from v in _context.Vehicles from r in _context.UnitRepairStatus(v.VehicleNumber) <-- ITVF reference orderby v.VehicleNumber select new FooViewModel { ID = v.ID,

我试图在Linq查询中引用内联表值函数ITVF:

var results = await (
    from v in _context.Vehicles
    from r in _context.UnitRepairStatus(v.VehicleNumber) <-- ITVF reference
    orderby v.VehicleNumber
    select new FooViewModel { 
            ID = v.ID, 
            VehicleNumber = v.VehicleNumber,
            InRepair = Convert.ToBoolean(r.InRepair) <-- ITFV field
        }
    ).ToListAsync();
如果删除ITFV引用,查询将按预期工作

var results = await (
    from v in _context.Vehicles
    orderby v.VehicleNumber
    select new FooViewModel { 
            ID = v.ID, 
            VehicleNumber = v.VehicleNumber,
            InRepair = False <-- dummy value
        }
    ).ToListAsync();
单元状态模型:

MyDatabasedContext数据库上下文:

public class MyDatabaseDbContext : DbContext
{

    public MyDatabaseDbContext(DbContextOptions<MyDatabaseDbContext> options) : base(options) {}
...

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        ...
        modelBuilder.Query<UnitRepairStatus>();
    }

    public IQueryable<UnitRepairStatus> UnitRepairStatus(string unitNumber) =>
        Query<UnitRepairStatus>().FromSql($"SELECT * FROM UnitRepairStatus({unitNumber})");

}
车辆控制器构造:

public VehiclesController(
    ILogger<VehiclesController> logger, 
    MyDatabaseDbContext context
)
{
    _logger = logger;
    _context = context;
}
参考:


对不起,是我的错。上一个问题的答案中的技术适用于使用常量/变量参数调用ITVF,但不适用于相关子查询,如您的案例和我的错误示例

解决方案是删除ITVF参数,并扩展结果以包括该列,同时有效地将其转换为无参数视图:

创建函数dbo.UnitRepairStatus 返回表 像 回来 在准备中选择u.UnitNumber,h 来自Schema2.u单元 内部联接模式2.u.ID上的历史h=h.UnitID 还要从上下文方法中删除该参数

EF Core 2.x:

public IQueryable<UnitRepairStatus> UnitRepairStatus() =>
    Query<UnitRepairStatus>().FromSql("SELECT * FROM UnitRepairStatus()");
EF Core 3.x:

public IQueryable<UnitRepairStatus> UnitRepairStatus() =>
    Set<UnitRepairStatus>().FromSqlRaw("SELECT * FROM UnitRepairStatus()");
并将LINQ查询更改为使用联接:

var results = await (
    from v in _context.Vehicles
    join r in _context.UnitRepairStatus() on v.VehicleNumber equals r.UnitNumber // <---
    orderby v.VehicleNumber
    select new FooViewModel { 
        ID = v.ID, 
        VehicleNumber = v.VehicleNumber,
        InRepair = Convert.ToBoolean(r.InRepair)
    }
).ToListAsync();
现在,它应该在服务器端翻译和执行,并在客户端成功实现


原始方法的问题是EF Core悄悄地将查询执行切换到客户端,然后在同一个上下文上执行多个异步操作,从而达到其保护作用。

使用无参数的TVF而不仅仅是视图有什么价值?如果没有,我可以消除IQueryable方法,将其定义为modelBuilder.queryUnitRepairStatus。您的代码的其余部分似乎可以按原样工作。原始方法的问题是EF Core会将查询执行悄悄地切换到客户端,然后在同一上下文上执行多个异步操作,从而达到保护效果。当我使用第二个上下文连接到另一个数据库时,我没有得到错误,可能是因为它没有达到操作限制。这也解释了为什么输出显示对函数的DB的重复调用。查询按预期进行了转换:从[Vehicles]中选择[v].[ID],[v].[VehicleNumber],[r].[InRepair]作为[v]上的[v]内部联接从UnitRepairStatus选择*作为[r]。[VehicleNumber]=[r].[UnitNumber]按[VehicleNumber]订购@craig的确,没有参数可以映射到视图。仍然使用函数更灵活-它允许您定义和传递一些其他非相关参数,并且在将来的某个时候,我希望对TVF集返回函数的支持将被添加,类似于v2.0中添加的对[Database scalar function mapping]的支持。上述技术只是当前EF核心限制的变通方法。
public VehiclesController(
    ILogger<VehiclesController> logger, 
    MyDatabaseDbContext context
)
{
    _logger = logger;
    _context = context;
}
public async Task<IActionResult> Foo()
{

    List<FooViewModel> model = null;

    try
    {
        var results = await (  <-- line referenced in error message
            from v in _context.Vehicles
            from r in _context.UnitRepairStatus(v.VehicleNumber)
            orderby v.VehicleNumber
            select new FooViewModel { 
                    ID = v.ID, 
                    VehicleNumber = v.VehicleNumber,
                    InRepair = Convert.ToBoolean(r.InRepair)
                }
            ).ToListAsync();

    }
    catch (Exception e)
    {
        _logger.LogError(e.Message);
        throw;
    }

    return View(model);

}
public IQueryable<UnitRepairStatus> UnitRepairStatus() =>
    Query<UnitRepairStatus>().FromSql("SELECT * FROM UnitRepairStatus()");
public IQueryable<UnitRepairStatus> UnitRepairStatus() =>
    Set<UnitRepairStatus>().FromSqlRaw("SELECT * FROM UnitRepairStatus()");
var results = await (
    from v in _context.Vehicles
    join r in _context.UnitRepairStatus() on v.VehicleNumber equals r.UnitNumber // <---
    orderby v.VehicleNumber
    select new FooViewModel { 
        ID = v.ID, 
        VehicleNumber = v.VehicleNumber,
        InRepair = Convert.ToBoolean(r.InRepair)
    }
).ToListAsync();