ASP.NET Web API 2 OData'da $select, $expand ve $value kullanma

tarafından Mike Wasson

ASP.NET 4.x için OData Web API 2'deki $expand, $select ve $value seçeneklerine genel bakış ve kod örnekleri. Bu seçenekler, istemcinin sunucudan geri aldığı gösterimi denetlemesine olanak sağlar.

  • $expand ilgili varlıkların yanıta satır içinde eklenmesine neden olur.
  • $select yanıta eklenecek özelliklerin bir alt kümesini seçer.
  • $value bir özelliğin ham değerini alır.

Örnek Şema

Bu makale için üç varlığı tanımlayan bir OData hizmeti kullanacağım: Product, Supplier ve Category. Her ürünün bir kategorisi ve bir tedarikçisi vardır.

Varlık olarak Ürünler, Tedarikçiler ve Kategoriler tanımlayarak O Veri hizmeti için örnek şemayı gösteren diyagram.

Varlık modellerini tanımlayan C# sınıfları şunlardır:

public class Supplier
{
    [Key]
    public string Key {get; set; }
    public string Name { get; set; }
}
public class Category
{
    public int ID { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Product> Products { get; set; }
}

public class Product
{
    public int ID { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }

    [ForeignKey("Category")]
    public int CategoryId { get; set; }
    public Category Category { get; set; }

    [ForeignKey("Supplier")]
    public string SupplierId { get; set; }
    public virtual Supplier Supplier { get; set; }
}

sınıfının ve Categoryiçin Supplier gezinti özelliklerini tanımladığını Product fark edin. Category sınıfı, her kategorideki ürünler için bir gezinti özelliği tanımlar.

Bu şema için bir OData uç noktası oluşturmak için, ASP.NET Web API'sinde OData Uç Noktası Oluşturma bölümünde açıklandığı gibi Visual Studio 2013 yapı iskelesini kullanın. Ürün, Kategori ve Tedarikçi için ayrı denetleyiciler ekleyin.

$expand ve $select etkinleştirme

Visual Studio 2013'de, Web API OData iskelesi $expand ve $select otomatik olarak destekleyen bir denetleyici oluşturur. Başvuru için, bir denetleyicide $expand ve $select destekleme gereksinimleri aşağıdadır.

Koleksiyonlar için denetleyicinin Get yöntemi bir IQueryable döndürmelidir.

[Queryable]
public IQueryable<Category> GetCategories()
{
    return db.Categories;
}

Tek varlıklar için, bir SingleResult<T> döndürür; burada T sıfır veya bir varlık içeren bir IQueryable'dır .

[Queryable]
public SingleResult<Category> GetCategory([FromODataUri] int key)
{
    return SingleResult.Create(db.Categories.Where(c => c.ID == key));
}

Ayrıca, önceki kod parçacıklarında gösterildiği gibi yöntemlerinizi Get[Queryable] özniteliğiyle süsleyin. Alternatif olarak, başlangıçta HttpConfiguration nesnesinde EnableQuerySupport'u çağırın. (Daha fazla bilgi için bkz . OData Sorgu Seçeneklerini Etkinleştirme.)

$expand kullanma

Bir OData varlığını veya koleksiyonunu sorguladığınızda, varsayılan yanıt ilgili varlıkları içermez. Örneğin, Kategoriler varlık kümesi için varsayılan yanıt aşağıda verilmiştir:

{
  "odata.metadata":"http://localhost/odata/$metadata#Categories",
  "value":[
    {"ID":1,"Name":"Apparel"},
    {"ID":2,"Name":"Toys"}
  ]
}

Gördüğünüz gibi, Kategori varlığında Ürünler gezinti bağlantısı olsa bile yanıt hiçbir ürün içermez. Ancak istemci, her kategoriye ait ürünlerin listesini almak için $expand kullanabilir. $expand seçeneği isteğin sorgu dizesine gider:

GET http://localhost/odata/Categories?$expand=Products

Artık sunucu her kategoriye ait ürünleri kategorilerle satır içi olarak içerecektir. Yanıt yükü şu şekildedir:

{
  "odata.metadata":"http://localhost/odata/$metadata#Categories",
  "value":[
    {
      "Products":[
        {"ID":1,"Name":"Hat","Price":"15.00","CategoryId":1,"SupplierId":"CTSO"},
        {"ID":2,"Name":"Scarf","Price":"12.00","CategoryId":1,"SupplierId":"CTSO"},
        {"ID":3,"Name":"Socks","Price":"5.00","CategoryId":1,"SupplierId":"FBRK"}
      ],
      "ID":1,
      "Name":"Apparel"
    },
    {
      "Products":[
        {"ID":4,"Name":"Yo-yo","Price":"4.95","CategoryId":2,"SupplierId":"WING"},
        {"ID":5,"Name":"Puzzle","Price":"8.00","CategoryId":2,"SupplierId":"WING"}
      ],
      "ID":2,
      "Name":"Toys"
    }
  ]
}

"value" dizisindeki her girişin bir Ürünler listesi içerdiğine dikkat edin.

$expand seçeneği, genişletmek için gezinti özelliklerinin virgülle ayrılmış bir listesini alır. Aşağıdaki istek, bir ürünün hem kategorisini hem de tedarikçisini genişletir.

GET http://localhost/odata/Products(1)?$expand=Category,Supplier

Yanıt gövdesi aşağıdadır:

{
  "odata.metadata":"http://localhost/odata/$metadata#Products/@Element",
  "Category": {"ID":1,"Name":"Apparel"},
  "Supplier":{"Key":"CTSO","Name":"Contoso, Ltd."},
  "ID":1,
  "Name":"Hat",
  "Price":"15.00",
  "CategoryId":1,
  "SupplierId":"CTSO"
}

Birden fazla gezinti özelliği düzeyini genişletebilirsiniz. Aşağıdaki örnek, bir kategoriye ilişkin tüm ürünleri ve her ürünün tedarikçisini içerir.

GET http://localhost/odata/Categories(1)?$expand=Products/Supplier

Yanıt gövdesi aşağıdadır:

{
  "odata.metadata":"http://localhost/odata/$metadata#Categories/@Element",
  "Products":[
    {
      "Supplier":{"Key":"CTSO","Name":"Contoso, Ltd."},
      "ID":1,"Name":"Hat","Price":"15.00","CategoryId":1,"SupplierId":"CTSO"
    },
    {
      "Supplier":{"Key":"CTSO","Name":"Contoso, Ltd."},
      "ID":2,"Name":"Scarf","Price":"12.00","CategoryId":1,"SupplierId":"CTSO"
    },{
      "Supplier":{
        "Key":"FBRK","Name":"Fabrikam, Inc."
      },"ID":3,"Name":"Socks","Price":"5.00","CategoryId":1,"SupplierId":"FBRK"
    }
  ],"ID":1,"Name":"Apparel"
}

Varsayılan olarak, Web API'si maksimum genişletme derinliğini 2 ile sınırlar. Bu, istemcinin gibi $expand=Orders/OrderDetails/Product/Supplier/Regionbüyük yanıtları sorgulamak ve oluşturmak için verimsiz olabilecek karmaşık istekler göndermesini engeller. Varsayılanı geçersiz kılmak için [Queryable] özniteliğinde MaxExpansionDepth özelliğini ayarlayın.

[Queryable(MaxExpansionDepth=4)]
public IQueryable<Category> GetCategories()
{
    return db.Categories;
}

$expand seçeneği hakkında daha fazla bilgi için resmi OData belgelerindeki Sistem Sorgu Seçeneğini ($expand) Genişletme bölümüne bakın.

$select kullanma

$select seçeneği, yanıt gövdesine eklenecek özelliklerin bir alt kümesini belirtir. Örneğin, her ürünün yalnızca adını ve fiyatını almak için aşağıdaki sorguyu kullanın:

GET http://localhost/odata/Products?$select=Price,Name

Yanıt gövdesi aşağıdadır:

{
  "odata.metadata":"http://localhost/odata/$metadata#Products&$select=Price,Name",
  "value":[
    {"Price":"15.00","Name":"Hat"},
    {"Price":"12.00","Name":"Scarf"},
    {"Price":"5.00","Name":"Socks"},
    {"Price":"4.95","Name":"Yo-yo"},
    {"Price":"8.00","Name":"Puzzle"}
  ]
}

$select ve $expand aynı sorguda birleştirebilirsiniz. genişletilmiş özelliğini $select seçeneğine eklediğinizden emin olun. Örneğin, aşağıdaki istek ürün adını ve sağlayıcıyı alır.

GET http://localhost/odata/Products?$select=Name,Supplier&$expand=Supplier

Yanıt gövdesi aşağıdadır:

{
  "odata.metadata":"http://localhost/odata/$metadata#Products&$select=Name,Supplier",
  "value":[
    {
      "Supplier":{"Key":"CTSO","Name":"Contoso, Ltd."},
      "Name":"Hat"
    },
    {
      "Supplier":{"Key":"CTSO","Name":"Contoso, Ltd."},
      "Name":"Scarf"
    },
    {
      "Supplier":{"Key":"FBRK","Name":"Fabrikam, Inc."},
      "Name":"Socks"
    },
    {
      "Supplier":{"Key":"WING","Name":"Wingtip Toys"},
      "Name":"Yo-yo"
    },
    {
      "Supplier":{"Key":"WING","Name":"Wingtip Toys"},
      "Name":"Puzzle"
   }
  ]
}

Genişletilmiş bir özellik içindeki özellikleri de seçebilirsiniz. Aşağıdaki istek Ürünler'i genişletir ve kategori adı ile ürün adını seçer.

GET http://localhost/odata/Categories?$expand=Products&$select=Name,Products/Name

Yanıt gövdesi aşağıdadır:

{
  "odata.metadata":"http://localhost/odata/$metadata#Categories&$select=Name,Products/Name",
  "value":[ 
    {
      "Products":[ {"Name":"Hat"},{"Name":"Scarf"},{"Name":"Socks"} ],
      "Name":"Apparel"
    },
    {
      "Products":[ {"Name":"Yo-yo"},{"Name":"Puzzle"} ],
      "Name":"Toys"
    }
  ]
}

$select seçeneği hakkında daha fazla bilgi için resmi OData belgelerindeki Sistem Sorgusu Seçeneğini ($select) Seçme bölümüne bakın.

Varlığın Tek Tek Özelliklerini Alma ($value)

OData istemcisinin bir varlıktan tek bir özelliği alması için iki yol vardır. İstemci değeri OData biçiminde alabilir veya özelliğin ham değerini alabilir.

Aşağıdaki istek OData biçiminde bir özellik alır.

GET http://localhost/odata/Products(1)/Name

JSON biçiminde bir örnek yanıt aşağıda verilmiştir:

HTTP/1.1 200 OK
Content-Type: application/json; odata=minimalmetadata; streaming=true; charset=utf-8
DataServiceVersion: 3.0
Content-Length: 90

{
  "odata.metadata":"http://localhost:14239/odata/$metadata#Edm.String",
  "value":"Hat"
}

Özelliğin ham değerini almak için URI'ye $value ekleme:

GET http://localhost/odata/Products(1)/Name/$value

Yanıtı burada bulabilirsiniz. İçerik türünün JSON değil "text/plain" olduğuna dikkat edin.

HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
DataServiceVersion: 3.0
Content-Length: 3

Hat

OData denetleyicinizde bu sorguları desteklemek için, özelliğinin adı olan Property adlı GetPropertybir yöntem ekleyin. Örneğin, Name özelliğini alma yöntemi olarak adlandırılır GetName. yöntemi bu özelliğin değerini döndürmelidir:

public async Task<IHttpActionResult> GetName(int key)
{
    Product product = await db.Products.FindAsync(key);
    if (product == null)
    {
        return NotFound();
    }
    return Ok(product.Name);
}