1

ASP.NET Web Api で OData クエリ可能な GET 要求を処理する正しい方法は何ですか? これは「何が優れているか」という質問のように聞こえるかもしれませんが、「何が機能するか」という質問であるべきです。

いくつかの仮定:

  • OData クエリを有効にするには、Queryableを返すアクション メソッドに属性を配置する必要がありますIQueryable<Model>。したがって、ドメイン モデルを公開する必要がありますか。
  • ドメイン モデルは Entity Framework 5 を使用し、ナビゲーション プロパティを備えています。XML および Json シリアライザーは EF プロキシを好まないため、OData クエリに対してそれらを無効にする必要がありますか?
  • シリアライザーはナビゲーション プロパティを取得し、ユーザーに提供します。

したがって、Category親と子のナビゲーション プロパティを持つ型がある場合、シリアライザーは循環参照があると文句を言い、このエラーを取り除くことはできません。

DTO を使用する必要があると読みましたが、どのようにすればよいですか? IQueryable<DTOModel>データベースに適切な SQL を作成するユーザーにどのように提供できますか? 覚えて、使いたい$filterなど。

シリアル化されたナビゲーション プロパティを使用せずに、フィルター可能なモデル オブジェクトのリストをユーザーに提供したいだけですが、どのようにすればよいでしょうか?

4

1 に答える 1

3

公開する必要はありません。IQueryable<>インスタンスを受け取り、ODataQueryOptionsこれを自分で処理するメソッドを作成できます。必要なことのほとんどを実行するコード サンプルを次に示します。自分に最適なソリューションを見つけ出すだけで十分です。この方法では、EF プロキシ クラスを保持することもできます。

using System.Web.Http.OData;
using System.Web.Http.OData.Builder;
using System.Web.Http.OData.Query;
[ActionName("Dto")]
public IList<DtoModel> GetDto(ODataQueryOptions<DtoModel> queryOptions)
{
    var data2 = DatabaseData();

    //Create a set of ODataQueryOptions for the internal class
    ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
    modelBuilder.EntitySet<Model>("Model");
    var queryContext = new ODataQueryContext(
         modelBuilder.GetEdmModel(), typeof(Model));
    var newQueryOptions = new ODataQueryOptions<Model>(queryContext, Request);

    var t = new ODataValidationSettings() { MaxTop = 25 };
    var s = new ODataQuerySettings() { PageSize = 25 };
    newQueryOptions.Validate(t);
    IEnumerable<Model> results =
        (IEnumerable<Model>)newQueryOptions.ApplyTo(data2, s);

    int skip = newQueryOptions.Skip == null ? 0 : newQueryOptions.Skip.Value;
    int take = newQueryOptions.Top == null ? 25 : newQueryOptions.Top.Value;

    IList<Model> internalResults = results.Skip(skip).Take(take).ToList();

    // map from Model to Dto here using AutoMapper
    AutoMapper.Mapper.CreateMap<Model, DtoModel>();
    IList<DtoModel> webResults =
        AutoMapper.Mapper.Map<IList<Model>, IList<DtoModel>>(internalResults);

    return webResults;
}

この例で使用されているデータは、単純なQueryableデータ セットです。

private IQueryable<Model> DatabaseData()
{
    return (
        new Model[] { 
        new Model() { id = 1, name = "one", type = "a" },
        new Model() { id = 2, name = "two", type = "b" },
        new Model() { id = 3, name = "three", type = "c" },
        new Model() { id = 4, name = "four", type = "d" },
        new Model() { id = 5, name = "five", type = "e" },
        new Model() { id = 6, name = "six", type = "f" },
        new Model() { id = 7, name = "seven", type = "g" },
        new Model() { id = 8, name = "eight", type = "h" },
        new Model() { id = 9, name = "nine", type = "i" }
    })
    .AsQueryable();
}

これらはテストクラスです:

public class Poco
{
    public int id { get; set; }
    public string name { get; set; }
    public string type { get; set; }
}
public class DtoModel
{
    public int id { get; set; }
    public string name { get; set; }
    public string type { get; set; }
}
public class Model
{
    public int id { get; set; }
    public string name { get; set; }
    public string type { get; set; }
    public virtual ICollection<Poco> Pocos { get; set; }
}
于 2013-09-05T14:33:42.390 に答える