Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
von Mike Wasson
Übersicht und Codebeispiele für die Optionen $expand, $select und $value in OData Web API 2 für ASP.NET 4.x. Mit diesen Optionen kann ein Client die Darstellung steuern, die er vom Server zurückgibt.
- $expand bewirkt, dass verwandte Entitäten inline in die Antwort eingeschlossen werden.
- $select wählt eine Teilmenge von Eigenschaften aus, die in die Antwort eingeschlossen werden sollen.
- $value ruft den Rohwert einer Eigenschaft ab.
Beispielschema
Für diesen Artikel verwende ich einen OData-Dienst, der drei Entitäten definiert: Produkt, Lieferant und Kategorie. Jedes Produkt verfügt über eine Kategorie und einen Lieferanten.
Hier sind die C#-Klassen, die die Entitätsmodelle definieren:
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; }
}
Beachten Sie, dass die Klasse Product Navigations-eigenschaften für Supplier und Category definiert. Die Category Klasse definiert eine Navigationseigenschaft für die Produkte in jeder Kategorie.
Verwenden Sie zum Erstellen eines OData-Endpunkts für dieses Schema das Visual Studio 2013-Gerüst, wie unter Erstellen eines OData-Endpunkts in ASP.NET Web-API beschrieben. Fügen Sie separate Controller für Produkt, Kategorie und Lieferant hinzu.
Aktivieren von $expand und $select
In Visual Studio 2013 erstellt das OData-Gerüst der Web-API einen Controller, der automatisch $expand und $select unterstützt. Hier sind die Anforderungen zur Unterstützung von $expand und $select in einem Controller.
Für Sammlungen muss die Methode des Controllers Get ein IQueryable zurückgeben.
[Queryable]
public IQueryable<Category> GetCategories()
{
return db.Categories;
}
Geben Sie für einzelne Entitäten ein SingleResult<T> zurück, wobei T ein IQueryable-Objekt ist, das null oder eine Entität enthält.
[Queryable]
public SingleResult<Category> GetCategory([FromODataUri] int key)
{
return SingleResult.Create(db.Categories.Where(c => c.ID == key));
}
Schmücken Sie ihre Get Methoden auch mit dem [Queryable] -Attribut, wie in den vorherigen Codeausschnitten gezeigt. Alternativ rufen Sie EnableQuerySupport beim Start auf das HttpConfiguration-Objekt auf. (Weitere Informationen finden Sie unter Aktivieren von OData-Abfrageoptionen.)
Verwenden von $expand
Wenn Sie eine OData-Entität oder -Auflistung abfragen, enthält die Standardantwort keine verwandten Entitäten. Hier ist z. B. die Standardantwort für den Entitätssatz "Categories":
{
"odata.metadata":"http://localhost/odata/$metadata#Categories",
"value":[
{"ID":1,"Name":"Apparel"},
{"ID":2,"Name":"Toys"}
]
}
Wie Sie sehen können, enthält die Antwort keine Produkte, obwohl die Kategorieentität über einen Navigationslink für Produkte verfügt. Der Client kann jedoch $expand verwenden, um die Liste der Produkte für jede Kategorie abzurufen. Die Option $expand wird in die Abfragezeichenfolge der Anforderung gesetzt:
GET http://localhost/odata/Categories?$expand=Products
Jetzt wird der Server die Produkte für jede Kategorie jeweils den Kategorien zugeordnet enthalten. Hier ist das Antwort-Payload:
{
"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"
}
]
}
Beachten Sie, dass jeder Eintrag im Array "Value" eine Produktliste enthält.
Die Option $expand verwendet eine durch Trennzeichen getrennte Liste der Navigationseigenschaften, um zu erweitern. Die folgende Anforderung erweitert sowohl die Kategorie als auch den Lieferanten für ein Produkt.
GET http://localhost/odata/Products(1)?$expand=Category,Supplier
Hier ist der Antworttext:
{
"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"
}
Sie können mehr als eine Ebene der Navigationseigenschaft erweitern. Das folgende Beispiel enthält alle Produkte für eine Kategorie und auch den Lieferanten für jedes Produkt.
GET http://localhost/odata/Categories(1)?$expand=Products/Supplier
Hier ist der Antworttext:
{
"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"
}
Standardmäßig beschränkt die Web-API die maximale Erweiterungstiefe auf 2. Dadurch wird verhindert, dass der Client komplexe Anforderungen wie $expand=Orders/OrderDetails/Product/Supplier/Region sendet, die ineffizient abfragbar sind und große Antworten erzeugen können. Um den Standardwert außer Kraft zu setzen, legen Sie die MaxExpansionDepth-Eigenschaft für das [Queryable] -Attribut fest.
[Queryable(MaxExpansionDepth=4)]
public IQueryable<Category> GetCategories()
{
return db.Categories;
}
Weitere Informationen zur option $expand finden Sie unter Erweitern der Systemabfrageoption ($expand) in der offiziellen OData-Dokumentation.
Verwenden von $select
Die Option $select gibt eine Teilmenge von Eigenschaften an, die in den Antworttext eingeschlossen werden sollen. Wenn Sie beispielsweise nur den Namen und den Preis jedes Produkts abrufen möchten, verwenden Sie die folgende Abfrage:
GET http://localhost/odata/Products?$select=Price,Name
Hier ist der Antworttext:
{
"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"}
]
}
Sie können $select und $expand in derselben Abfrage kombinieren. Stellen Sie sicher, dass Sie die erweiterte Eigenschaft in die Option $select einschließen. Die folgende Anforderung ruft z. B. den Produktnamen und den Lieferanten ab.
GET http://localhost/odata/Products?$select=Name,Supplier&$expand=Supplier
Hier ist der Antworttext:
{
"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"
}
]
}
Sie können auch die Eigenschaften in einer erweiterten Eigenschaft auswählen. Die folgende Anforderung erweitert Produkte und wählt Kategoriename plus Produktname aus.
GET http://localhost/odata/Categories?$expand=Products&$select=Name,Products/Name
Hier ist der Antworttext:
{
"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"
}
]
}
Weitere Informationen zur option $select finden Sie in der offiziellen OData-Dokumentation unter Auswahl der Systemabfrageoption ($select ).
Abrufen einzelner Eigenschaften einer Entität ($value)
Es gibt zwei Möglichkeiten für einen OData-Client, eine einzelne Eigenschaft aus einer Entität abzurufen. Der Client kann entweder den Wert im OData-Format abrufen oder den Rohwert der Eigenschaft abrufen.
Die folgende Anforderung ruft eine Eigenschaft im OData-Format ab.
GET http://localhost/odata/Products(1)/Name
Hier ist eine Beispielantwort im JSON-Format:
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"
}
Um den Rohwert der Eigenschaft abzurufen, fügen Sie $value an den URI an:
GET http://localhost/odata/Products(1)/Name/$value
Hier ist die Antwort. Beachten Sie, dass der Inhaltstyp "text/plain" ist, nicht JSON.
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
DataServiceVersion: 3.0
Content-Length: 3
Hat
Um diese Abfragen in Ihrem OData-Controller zu unterstützen, fügen Sie eine Methode mit dem Namen GetPropertyhinzu, wobei Property es sich um den Namen der Eigenschaft handelt. Die Methode zum Abrufen der Eigenschaft "Name" würde z. B. GetName genannt werden. Die Methode sollte den Wert dieser Eigenschaft zurückgeben:
public async Task<IHttpActionResult> GetName(int key)
{
Product product = await db.Products.FindAsync(key);
if (product == null)
{
return NotFound();
}
return Ok(product.Name);
}