Typically, an OData EDM (Entity Data Model) is defined at the time of configuration before it can be queried or performed on various operations. such as the following:
Builder. Entityset<somemodel> ("somemodels");
This may be a query: Http://localhost:8888/odata/SomeModels
If there is a collection navigation property in Somemodel, how do I get it? Like what:
Public class somemodel{ publicint id{get; Set;} Public ilist<anothermodel> anothermodels{get; Set;}} Public class anothermodel{
Whether we can get all the Anothermodel directly in Somemodel, instead of getting it in the following way:
Builder. Entityset<anothermodel> ("anothermodels"); http:// Localhost:8888/odata/anothermodels
OData provides us with containment, as long as you add the [Contained] attribute to a collection navigation property, you can get the collection navigation properties under an EDM model as follows:
http://localhost:8888/odata/somemodels (1)/anothermodels
Well, define the model first.
Public classaccount{ Public intAccountID {Get;Set; } Public stringName {Get;Set; } [Contained] PublicIlist<paymentinstrument> Payinpis {Get;Set; }} Public classpaymentinstrument{ Public intPaymentinstrumentid {Get;Set; } Public stringFriendlyName {Get;Set; }}
Above, once the [Contained] feature is added to the set navigation property of Payinpis, as long as the method of acquiring the set navigation property is provided in the controller, we can get the Paymentinstrument collection through the account as follows. As follows:
http://localhost:8888/odata/accounts (/payinpis)
The following are defined in the Webapiconfig class:
Public Static classwebapiconfig{ Public Static voidRegister (httpconfiguration config) {... config. Mapodataserviceroute (routeName:"Odataroute", Routeprefix:"OData", Model:getmodel ()); } Private StaticIedmmodel Getmodel () {Odataconventionmodelbuilder builder=NewOdataconventionmodelbuilder (); Builder. EntityType<PaymentInstrument>(); Builder. EntitySet<Account> ("Accounts"); returnBuilder. Getedmmodel (); }}
The API-side definitions are as follows:
Public classaccountscontroller:odatacontroller{Private StaticIlist<account> _accounts =NULL; PublicAccountscontroller () {if(_accounts==NULL) {_accounts=initaccounts (); }} [Enablequery] PublicIhttpactionresult Get () {returnOk (_accounts. AsQueryable ()); } [Enablequery] PublicIhttpactionresult GetById ([Fromodatauri]intkey) { varaccount = _accounts. Single (a = A.accountid = =key); returnOk (account); } //get the account all Paymentinstrument collection[Enablequery] PublicIhttpactionresult Getpayinpis ([Fromodatauri]intkey) { varPayinpis = _accounts. Single (a = A.accountid = =key). Payinpis; returnOk (Payinpis); } Private StaticIlist<account>initaccounts () {varaccounts =NewList<account>() { NewAccount () {AccountID= -, Name="Name100", PAYOUTPI=Newpaymentinstrument () {Paymentinstrumentid= -, FriendlyName="Payout Pi:paypal",}, Payinpis=NewList<paymentinstrument>() { Newpaymentinstrument () {Paymentinstrumentid=101, FriendlyName="101 First PI", }, Newpaymentinstrument () {Paymentinstrumentid=102, FriendlyName="102 Second PI", }, }, }, }; returnaccounts; }}
The Getpayinpis method above allows us to get its collection navigation property Payinpis according to the account.
Well, now that Payinpis adds the [Contained] feature, it also comes with a specific action, and now starts querying:
http://localhost:64696/odata/accounts (/payinpis)
All the paymentinstrument can be queried.
At this point, how does the Payinpis collection navigation property appear in the metadata? The query is as follows:
http://localhost:64696/odata/$metadata
The relevant sections are:
<entitytype name=" Account"> <Key> <propertyref name="AccountID"/> </Key> <property name="AccountID"Type="Edm.int32"nullable="false"/> <property name="Name"Type="edm.string"/> <navigationproperty name="Payinpis"Type="Collection (myodatacontainmentsample.paymentinstrument)"containstarget="true"/></entitytype>
What if the [Contained] feature on the Payinpis is removed? Remove and then query again as follows:
http://localhost:64696/odata/accounts (/payinpis)
Returns 404 Not FOUND
Then take a look at the metadata associated with removing the [Contained] attribute:
<navigationproperty name= "Payinpis" type= "Collection (myodatacontainmentsample.paymentinstrument)"/>
Before the [Contained] feature is removed:
<navigationproperty name= "Payinpis" type= "Collection (myodatacontainmentsample.paymentinstrument)" Containstarget= "true"/>
Originally, adding the [Contained] attribute on a collection navigation property is actually letting containstarget= "true", and by default, containstarget= "false".
^_^
Using OData containment in the ASP. NET Web API