在ASP.NET Web API中使用OData的Containment

 

通常情况下,一个OData的EDM(Entity Data Model)在配置的时候定义了,才可以被查询或执行各种操作。比如如下:

 

builder.EntitySet<SomeModel>("SomeModels");

 

可能会这样查询:http://localhost:8888/odata/SomeModels

 

如果SomeModel中有一个集合导航属性,该如何获取呢?比如:

 

public class SomeModel
{
    public int Id{get;set;}
    
    public IList<AnotherModel> AnotherModels{get;set;}
}

public class AnotherModel
{
  

 

我们是否可以直接在SomeModel中获取所有的AnotherModel, 而不是通过如下方式获取:

 

builder.EntitySet<AnotherModel>("AnotherModels");
http://localhost:8888/odata/AnotherModels

 

OData为我们提供了Containment,只要为某个集合导航属性加上[Contained]特性,就可以按如下方式获取某个EDM模型下的集合导航属性,比如:

 

http://localhost:8888/odata/SomeModels(1)/AnotherModels

 

好先定义模型。

 

public class Account
{
    public int AccountID { get; set; }
    public string Name { get; set; }

    [Contained]
    public IList<PaymentInstrument> PayinPIs { get; set; }
}

public class PaymentInstrument
{
    public int PaymentInstrumentID { get; set; }
    public string FriendlyName { get; set; }
}

 

以上,一旦在PayinPIs这个集合导航属性上加上[Contained]特性,只要在controller中再提供获取集合导航属性的方法,我们就可以按如下方式,通过Account获取PaymentInstrument集合。如下:

 

http://localhost:8888/odata/Accounts(100)/PayinPIs

 

在WebApiConfig类中定义如下:

 

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        ...

        config.MapODataServiceRoute(
            routeName: "ODataRoute",
            routePrefix: "odata",
            model: GetModel());
    }

    private static IEdmModel GetModel()
    {
        ODataConventionModelBuilder builder = new ODataConventionModelBuilder();

        builder.EntityType<PaymentInstrument>();
        builder.EntitySet<Account>("Accounts");

        return builder.GetEdmModel();
    }
}

 


在API端定义如下:

 

public class AccountsController : ODataController
{

    private static IList<Account> _accounts = null;

    public AccountsController()
    {
        if(_accounts==null)
        {
            _accounts = InitAccounts();
        }
    }

    [EnableQuery]
    public IHttpActionResult Get()
    {
        return Ok(_accounts.AsQueryable());
    }

    [EnableQuery]
    public IHttpActionResult GetById([FromODataUri] int key)
    {
        var account = _accounts.Single(a => a.AccountID == key);
        return Ok(account);
    }

    //获取Account所有的PaymentInstrument集合
    [EnableQuery]
    public IHttpActionResult GetPayinPIs([FromODataUri]int key)
    {
        var payinPIs = _accounts.Single(a => a.AccountID == key).PayinPIs;
        return Ok(payinPIs);
    }

    private static IList<Account> InitAccounts()
    {
        var accounts = new List<Account>()
        {
            new Account()
            {
               AccountID = 100,
               Name="Name100",
               PayoutPI = new PaymentInstrument()
               {
                   PaymentInstrumentID = 100,
                   FriendlyName = "Payout PI: Paypal",
               },
                PayinPIs = new List<PaymentInstrument>()
                {
                    new PaymentInstrument()
                    {
                        PaymentInstrumentID = 101,
                        FriendlyName = "101 first PI",
                    },
                    new PaymentInstrument()
                    {
                        PaymentInstrumentID = 102,
                        FriendlyName = "102 second PI",
                    },
                },
            },
        };
        return accounts;
    }
}

 

以上的GetPayinPIs方法可以让我们根据Account获取其集合导航属性PayinPIs。


好,现在PayinPIs加上了[Contained]特性,也配备了具体的Action,现在开始查询:

 

http://localhost:64696/odata/Accounts(100)/PayinPIs

 

能查询到所有的PaymentInstrument。

 

此时,PayinPIs集合导航属性在元数据中是如何呈现的呢?查询如下:

 

http://localhost:64696/odata/$metadata

 

相关部分为:

 

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

 

如果把PayinPIs上的[Contained]特性去掉呢?去掉后再次查询如下:

 

http://localhost:64696/odata/Accounts(100)/PayinPIs

 

返回404 NOT FOUND

 

再来看去掉[Contained]特性后相关的元数据:

<NavigationProperty Name="PayinPIs" Type="Collection(MyODataContainmentSample.PaymentInstrument)" />


没去掉[Contained]特性之前是:
<NavigationProperty Name="PayinPIs" Type="Collection(MyODataContainmentSample.PaymentInstrument)" ContainsTarget="true" />

 

原来,在一个集合导航属性上添加[Contained]特性,实际是让ContainsTarget="true",而默认状况下,ContainsTarget="false"。

 

 ^_^     

 

posted @ 2015-11-10 00:11  Darren Ji  阅读(596)  评论(0编辑  收藏  举报

我的公众号:新语新世界,欢迎关注。