【问题标题】:OData ASP.Net Core Get Related EntitiesOData ASP.Net Core 获取相关实体
【发布时间】:2018-05-05 04:01:26
【问题描述】:

我有一个 OData Beta + ASP.Net Core + EF 项目。我正在尝试解决 OData 控制器功能,但在尝试返回相关实体时遇到错误:

模型/Customer.cs

public class Customer
{
    public int Id { get; set; }
    public string Standing { get; set; }

    public List<Person> People { get; set; }
    public List<Address> Addresses { get; set; }
}

CustomersController.cs

using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Bookings_Server.EF;
using Bookings_Server.OData.Models;
using Microsoft.AspNet.OData;
using Microsoft.AspNet.OData.Routing;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Http;

namespace Bookings_Server.OData.Controllers
{
    [Produces("application/json")]
    [ODataRoutePrefix("customers")]
    public class CustomersController : ODataController
    {
        private readonly DataContext _context;

        public CustomersController(DataContext context)
        {
            _context = context;
        }

[EnableQuery]
[ODataRoute("({key})/people")]
public IQueryable<Customer> GetPeople([FromODataUri] int key)
{
    var result = _context.Customers.Where(m => m.Id == key).Select(m => m.People).ToList();
    return (result);
}
}

我在结果变量(在返回中)下收到一个智能感知错误,说明:

Cannot implicitly convert type 'System.Collections.Generic.List<System.Collections.Generic.List<Bookings_Server.OData.Models.Person>>' to 'System.Linq.IQueryable<Bookings_Server.OData.Models.Customer>'. An explicit conversion exists (are you missing a cast?)

我一直在查看其他 OData V4 示例,但它们都会引发隐式转换错误(假设这是在 Aps.Net Core 上工作的不同之处)。

【问题讨论】:

    标签: c# asp.net-core odata


    【解决方案1】:

    首先:您需要了解IQueryable&lt;T&gt;(表示(通常)数据库查询)与IEnumerable&lt;T&gt;(表示内存中的集合或数据源)之间的区别。所以:

    // WRONG
    public IQueryable<Customer> GetPeople([FromODataUri] int key)
    
    // CORRECT
    public IEnumerable<Customer> GetPeople([FromODataUri] int key) 
    

    您永远不应该将实体框架查询返回到您的应用程序之外。

    其次,您希望包含来自相关实体的数据,而不是选择该数据。所以:

    // WRONG
    return _context.Customers
        .Where(m => m.Id == key)
        .Select(m => m.People) // "only give me People data"
        .ToList();
    
    // CORRECT
    return _context.Customers
        .Where(m => m.Id == key)
        .Include(m => m.People) // "give me Customer WITH People data"
        .ToList();
    

    混合这些结构,你会得到:

    [EnableQuery]
    [ODataRoute("customers({key})/people")]
    public IEnumerable<Customer> GetPeople([FromODataUri] int key)
    {
        return _context.Customers
            .Where(m => m.Id == key)
            .Include(m => m.People)
            .ToList();
    }
    

    还有一点需要注意的是,您应该始终使用 Entity Framework Core 的数据访问方法的异步版本:

    [EnableQuery]
    [ODataRoute("customers({key})/people")]
    public async Task<IEnumerable<Customer>> GetPeople([FromODataUri] int key)
    {
        return await _context.Customers
            .Where(m => m.Id == key)
            .Include(m => m.People)
            .ToListAsync();
    }
    

    作为最后的评论,您应该更喜欢返回内置的IActionResult,它允许您轻松更改响应而无需引发异常:

    [EnableQuery]
    [ODataRoute("customers({key})/people")]
    public async Task<IActionResult> GetPeople([FromODataUri] int key)
    {
        var customers = await _context.Customers
            .Where(m => m.Id == key)
            .Include(m => m.People)
            .ToListAsync();
    
        // this is only an example
        if (!customers.Any())
        {
            return NotFound();
        }
    
        return Ok(customers);
    }
    

    【讨论】:

    • 谢谢@camilo!作为一个刚接触开发的人,我仍处于猴看猴做阶段,所以你清晰而仔细的回答非常适合帮助我学习,而不仅仅是解决问题!非常感谢!!!您的最终代码块对我来说不太适用。添加缺少的命名空间后,我仍然收到the name Json does not exist in the current context,所以我将继续尝试找出如何解决这个问题。干杯,亚当
    • @leadfollowmove 在这里表示感谢的方式是通过投票和接受有用的答案 :) 对于最后一个块,我假设该方法位于继承 Controller 的类中,但假设是我看错了。可以添加类声明吗?
    • 感谢更新。我编辑了控制器类的详细信息以显示控制器的其余部分(减去工作功能),希望能提供足够的信息来显示我所缺少的内容。干杯,亚当
    • @leadfollowmove 啊,看来你应该用Ok而不是Json,我已经更新了答案
    • 只是为了让事情变得复杂,我今天早上碰巧尝试了它,但它不起作用。智能感知很高兴,但我在运行时收到内部服务器错误:An unhandled exception occurred while processing the request. InvalidOperationException: The path template 'customers({key})/people' on the action 'GetPeople' in controller 'Customers' is not a valid OData path template. Found an unresolved path segment 'people' in the OData path template 'customers({key})/people'.
    【解决方案2】:

    好的。在一些帮助下,我设法解决了这个问题。我没有意识到 [OdataRoute] 是区分大小写的,它在我的模型中提取 People,并且在我的控制器中是人这一事实存在问题。

    改变了这一点,一切都开始按照@camilo 的建议工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      • 2020-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多