Bagikan melalui


Menggunakan $select, $expand, dan $value di ASP.NET Web API 2 OData

oleh Mike Wasson

Gambaran umum dan sampel kode untuk opsi $expand, $select, dan $value di OData Web API 2 untuk ASP.NET 4.x. Opsi ini memungkinkan klien untuk mengontrol representasi yang didapatkannya kembali dari server.

  • $expand menyebabkan entitas terkait disertakan sebaris dalam respons.
  • $select memilih subset properti untuk disertakan dalam respons.
  • $value mendapatkan nilai mentah properti.

Contoh Skema

Untuk artikel ini, saya akan menggunakan layanan OData yang menentukan tiga entitas: Produk, Pemasok, dan Kategori. Setiap produk memiliki satu kategori dan satu pemasok.

Diagram yang menunjukkan skema sampel untuk layanan Data O, menentukan Produk, Pemasok, dan Kategori sebagai entitasnya.

Berikut adalah kelas C# yang menentukan model entitas:

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; }
}

Perhatikan bahwa Product kelas menentukan properti navigasi untuk Supplier dan Category. Kelas Category menentukan properti navigasi untuk produk di setiap kategori.

Untuk membuat titik akhir OData untuk skema ini, gunakan perancah Visual Studio 2013, seperti yang dijelaskan dalam Membuat Titik Akhir OData di ASP.NET Web API. Tambahkan pengontrol terpisah untuk Produk, Kategori, dan Pemasok.

Mengaktifkan $expand dan $select

Di Visual Studio 2013, perancah OData API Web membuat pengontrol yang secara otomatis mendukung $expand dan $select. Sebagai referensi, berikut adalah persyaratan untuk mendukung $expand dan $select dalam pengontrol.

Untuk koleksi, metode pengontrol Get harus mengembalikan IQueryable.

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

Untuk entitas tunggal, kembalikan T> SingleResult<, di mana T adalah IQueryable yang berisi nol atau satu entitas.

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

Selain itu, hiasi metode Anda Get dengan atribut [Queryable ], seperti yang ditunjukkan pada cuplikan kode sebelumnya. Atau, panggil EnableQuerySupport pada objek HttpConfiguration saat startup. (Untuk informasi selengkapnya, lihat Mengaktifkan Opsi Kueri OData.)

Menggunakan $expand

Saat Anda mengkueri entitas atau koleksi OData, respons default tidak menyertakan entitas terkait. Misalnya, berikut adalah respons default untuk kumpulan entitas Kategori:

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

Seperti yang Anda lihat, respons tidak menyertakan produk apa pun, meskipun entitas Kategori memiliki tautan navigasi Produk. Namun, klien dapat menggunakan $expand untuk mendapatkan daftar produk untuk setiap kategori. Opsi $expand masuk dalam string kueri permintaan:

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

Sekarang server akan menyertakan produk untuk setiap kategori, sebaris dengan kategori. Berikut adalah payload respons:

{
  "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"
    }
  ]
}

Perhatikan bahwa setiap entri dalam array "nilai" berisi daftar Produk.

Opsi $expand mengambil daftar properti navigasi yang dipisahkan koma untuk diperluas. Permintaan berikut memperluas kategori dan pemasok untuk produk.

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

Berikut isi responsnya:

{
  "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"
}

Anda dapat memperluas lebih dari satu tingkat properti navigasi. Contoh berikut mencakup semua produk untuk kategori dan juga pemasok untuk setiap produk.

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

Berikut isi responsnya:

{
  "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"
}

Secara default, Web API membatasi kedalaman ekspansi maksimum menjadi 2. Itu mencegah klien mengirim permintaan kompleks seperti $expand=Orders/OrderDetails/Product/Supplier/Region, yang mungkin tidak efisien untuk mengkueri dan membuat respons besar. Untuk mengambil alih default, atur properti MaxExpansionDepth pada atribut [Queryable ].

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

Untuk informasi selengkapnya tentang opsi $expand, lihat Memperluas Opsi Kueri Sistem ($expand) dalam dokumentasi OData resmi.

Menggunakan $select

Opsi $select menentukan subset properti untuk disertakan dalam isi respons. Misalnya, untuk mendapatkan nama dan harga setiap produk saja, gunakan kueri berikut:

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

Berikut isi responsnya:

{
  "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"}
  ]
}

Anda bisa menggabungkan $select dan $expand dalam kueri yang sama. Pastikan untuk menyertakan properti yang diperluas dalam opsi $select. Misalnya, permintaan berikut mendapatkan nama produk dan pemasok.

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

Berikut isi responsnya:

{
  "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"
   }
  ]
}

Anda juga dapat memilih properti dalam properti yang diperluas. Permintaan berikut memperluas Produk dan memilih nama kategori ditambah nama produk.

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

Berikut isi responsnya:

{
  "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"
    }
  ]
}

Untuk informasi selengkapnya tentang opsi $select, lihat Pilih Opsi Kueri Sistem ($select) dalam dokumentasi OData resmi.

Mendapatkan Properti Individual Entitas ($value)

Ada dua cara bagi klien OData untuk mendapatkan properti individual dari entitas. Klien bisa mendapatkan nilai dalam format OData, atau mendapatkan nilai mentah properti.

Permintaan berikut mendapatkan properti dalam format OData.

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

Berikut adalah contoh respons dalam format JSON:

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"
}

Untuk mendapatkan nilai mentah properti, tambahkan $value ke URI:

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

Berikut adalah responsnya. Perhatikan bahwa jenis konten adalah "teks/biasa", bukan JSON.

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

Hat

Untuk mendukung kueri ini di pengontrol OData Anda, tambahkan metode bernama GetProperty, di mana Property adalah nama properti . Misalnya, metode untuk mendapatkan properti Nama akan diberi nama GetName. Metode harus mengembalikan nilai properti tersebut:

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