是否可以在ODataController中返回不同的模型?

时间:2017-10-04 08:34:11

标签: c# asp.net-web-api odata

在OData v4控制器中,是否可以为Get()Get([FromIDataUri] key)返回不同的模型?

我喜欢使用ViewModels,在使用Get()方法时,我想要返回xxxOverviewViewModel。使用Get([FromIDataUri] key)方法时,我想返回xxxViewModel。

这是可能的,如果是的话,怎么样?

我试图返回不同的模型,但我总是得到406 Acceptable

Webapi.config:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.EnableCors();

        config.MapODataServiceRoute("ODataRoute", "odata", GetEdmModel());

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        config.Filter().Expand().Select().OrderBy().MaxTop(null).Count();
    }

    private static IEdmModel GetEdmModel()
    {
        var builder = new ODataConventionModelBuilder();
        builder.EntitySet<ComplaintViewModel>("ComplaintOData");
        return builder.GetEdmModel();

    }
}

ComplaintODataController

public class ComplaintODataController : ODataController
{
    private readonly QueryProcessor _queryProcessor;

    public ComplaintODataController(QueryProcessor queryProcessor)
    {
        _queryProcessor = queryProcessor;
    }

    [EnableQuery]
    public IQueryable<ComplaintOverviewViewModel> Get()
    {
        var result = _queryProcessor.Handle(new GetAllComplaintsQuery());
        return result;
    }

    // WHEN CALLING THIS METHOD I GET A 406: 
    [EnableQuery]
    public ComplaintViewModel Get([FromODataUri] int key)
    {
        var result = _queryProcessor.Handle(new GetComplaintByIdQuery { Id = key });
        return result;
    }
}

编辑:

我的GetAllComplaintsQuery.Handle方法如下所示:

public IQueryable<ComplaintOverviewViewModel> Handle(GetAllComplaintsQuery query)
{
    // .All is an IQueryable<Complaint>
    var result = _unitOfWork.Complaints.All.Select(c => new ComplaintOverviewViewModel
    {
        ComplaintType = c.ComplaintType.Description,
        CreationDate = c.CreationDate,
        Customer = c.Customer,
        Description = c.Description,
        Id = c.Id,
        SequenceNumber = c.SequenceNumber,
        Creator = c.Creator.Name
    });

    return result;
}

这是我的ComplaintConfiguration

public class ComplaintConfiguration : EntityTypeConfiguration<Complaint>
{
    public ComplaintConfiguration()
    {
        Property(p => p.SequenceNumber).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
        Property(p => p.Description).IsRequired();
    }
}

3 个答案:

答案 0 :(得分:1)

您没有包含 ViewModel 类的定义,因此,首先请确保我们在同一页面上了解您实际尝试实现的目标。

当客户端从参数较少的Get()请求投诉记录列表但客户端请求{的特定投诉时,您似乎想要返回一些受限制的字段集{1}}您想要包含其他字段的方法。

我使用以下层次建模了这个假设:

Get([FromODataUri] int key)

Ran测试,public class ComplaintTypeViewModel { public int Id { get; set; } } public class ComplaintOverviewViewModel : ComplaintTypeViewModel { public string Name { get; set; } } public class ComplaintViewModel : ComplaintOverviewViewModel { public string Details { get; set; } } 按预期返回了一个只有 Id 名称的列表,GET /odata/ComplaintOData返回了一条包含详细信息的记录除了其他两个字段之外,也是预期的。

我从来没有必要更改控制器或GET /odata/ComplaintOData(1)的代码,但WebApiConfig.cs中的字符串参数必须与ccontroller匹配(您的代码中有builder.EntitySet<ComplaintTypeViewModel>("ComplaintOData");)。< / p>

由于它有效,我试图找出如何重现你的406.我已经改变"ComplaintTypeOData"直接延长ComplaintViewModel而不是延伸ComplaintTypeViewModel(注意我和#39;我刚刚复制了ComplaintOverviewViewModel属性:

Name

这也很好。

我可以重现406的唯一方法是将public class ComplaintTypeViewModel { public int Id { get; set; } } public class ComplaintOverviewViewModel : ComplaintTypeViewModel { public string Name { get; set; } } public class ComplaintViewModel : ComplaintTypeViewModel { public string Name { get; set; } public string Details { get; set; } } 更改为而不是在其继承层次结构中有ComplaintViewModel

ComplaintTypeViewModel

这最终给了我来自public class ComplaintTypeViewModel { public int Id { get; set; } } public class ComplaintOverviewViewModel : ComplaintTypeViewModel { public string Name { get; set; } } public class ComplaintViewModel { public int Id { get; set; } public string Name { get; set; } public string Details { get; set; } } 的406代码,而GET /odata/ComplaintOData(1)仍然使用 Id 名称返回列表就好了。

因此,只要 ViewModel 类的全部GET /odata/ComplaintOData延伸相同的T,您就可以返回其中的任何一个来自控制器中的builder.EntitySet<T>("name")重载。请检查您如何定义 ViewModels

答案 1 :(得分:0)

为两个模型创建一个伞类,并让你的get方法分别返回你想要的。

public class myMainModel
{
  public xxxOverviewViewModel x {get;set;}
  public xxxOverviewViewModel y {get;set;}
}

myMainModel Get()
{ 
  ....
  return myMainModel.x;
}

myMainModel Get( int key)
{ 
  ....
  return myMainModel.y;
}

答案 2 :(得分:0)

尝试从行动中删除SELECT t1.* FROM prd_data t1 WHERE t1.id = (SELECT t2.id FROM prd_data t2 WHERE t2.sub_prd_id= t1.sub_prd_id ORDER BY t2.created_at DESC LIMIT 1)

[EnableQuery]

public ComplaintViewModel Get([FromODataUri] int key)使用OData查询语法启用查询。集合EnableQueryAttribute是可以接受的。如果要返回单个实体,请不要使用该属性。

<强>更新

还尝试将参数IQueryable<>重命名为int key