2016-06-12 10 views
3

アプリケーションのデータを照会するためのOData構文を追加したいとします。私は完全にODataControllerを実装したいのですが、ApiControllerを持っており、ここで説明したように、ODataのクエリをサポートします1つのGETアクションを実装していない:私は持っていたいもののSupporting OData Query Options in ASP.NET Web API 2クライアントとサーバーを結合せずにODataをWeb API 2に追加

例:

public class LetterEntity 
    { 
     public int Id {get; set;} 

     public string Title {get; set;} 

     public string Content {get; set;} 

     public string Source {get; set;} 

     public DateTime SendingTime {get; set;} 

     public string AnotherWierdString {get; set; 
     ... 
    } 

    public class LetterDTO 
    { 
     public int Id {get; set;} 

     public string Title {get; set;} 

     public string LetterContent {get; set;} 

     public string Source {get; set;} 

     public DateTime SendingTime {get; set;} 
    } 

    public class LetterInsideFolderDTO 
    { 
     public string Title {get; set;} 

     public string Source {get; set;} 
    } 


public class LettersController : ApiController 
{   
    // Is there a way to do something like the following?: 
    [HttpGet] 
    [Route("api/letters")] 
    [EnableQuery] 
    public IQueryable<LetterInsideFolderDTO> Get(ODataQueryOptions<LetterDTO> query) 
    { 
     IQueryable<Letter> letters = db.Letters; 

     var queryOnEntites = // Convert the query to work on the entities somehow? - This is where I need help!! 

     var afterQuery = query.ApplyTo(letters) 

     IQueryable<LetterInsideFolderDTO> dtos = afterQuery.ProjectTo<LetterInsideFolderDTO>(afterQuery) 

     return dtos; 
    } 
} 

のので現時点では、クライアントクエリでEntityモデルを直接取得するという事実は、クライアントとサーバーの間に強力な結合が存在することを示しています。私はクエリを実行し、Contentフィールド内の「ABC」を持っているすべての文字を取得したい場合たとえば は、私は次のようにルーティングする必要があります。

api/letters/?$filter=contains(Content,'abc') 

明日、私は「コンテンツ」からそのプロパティを変更することを決定した場合"LetterContent"にすべてのクライアントコードが壊れます。

どうすればいいですか?

答えて

1

エンティティモデルを直接公開する代わりに、各エンティティモデルに対応するViewModelを作成します。彼らは、外界に暴露されたい、同じか、または必要な性質を持つ単純なクラスだけです。この方法を実装すると、エンティティモデルのプロパティは変更される可能性がありますが、ViewModelは変更されません。エンティティのすべてのプロパティをエンド・クライアントに公開しないというセキュリティ面にも取り組んでいます。

エンティティモデルとViewModel間のマッピングは、自分で行うか、AutoMapperのようなオブジェクトオブジェクトマッパーで行う必要があります。

+0

私はDtoが何であるか知っています。私はDtosとAutomapperも使用しますが、それは私が尋ねたものではありません。私は何とかODataQueryOptions を取って、それをODataQueryOptions に変換できるかどうか尋ねました。 –

1

私はそれを試していません。 Thisthisあなたはこれが(Nhibrenateのためわからないが、おそらくん)Entity Frameworkのために働くだろうLetterEntity

1

にLetterDtoをマッピングすることができ、ルータのマップとコントローラセレクタを使用して、実際のコントローラにクエリURLをマッピングするためにあなたを助けることができると行います実際のSQLクエリはメモリフィルタリングではありません。

var queryOnEntites = db.Letters.Select(l=>new LetterDTO{Id =l.Id ... }); 

var afterQuery = query.ApplyTo(queryOnEntites); 

しかし、あなたは今すぐbuilder.EntitySet<T1>("TEndpoint").EntityType.Ignore(o => o.SomeProp); を使用するAPIにはいくつかのプロパティをプライベートにしたい場合は、クライアントに送信された全体LetterEntityしたくない場合は、ODATAとのDTOを使用しないでください、あなたは$ = IDを選択してい、...この目的のためのオプション。 設定しない場合は、 config.MapODataServiceRoute( routeName: "ODataRoute", routePrefix: null, model: builder.GetEdmModel()); はOdataエンドポイントがなく、$ metadataは使用できません。 私はそれをテストしていませんが、クライアントライブラリ(.net、java、js ...)は動作しないと思うので、データを取得するために生のajaxリクエストを作成する必要があります。

ODataQueryOptions <>とそれを翻訳

> < ODataQueryOptions にあなたはこれを行うことはできません。 ProjectTo(AutoMapper)機能用量は.Select(l=>new LetterDTO{Id =l.Id ... });と同じですが、これに問題があります。 IQueryableはIEnumerableと同じではないので、これはすべてバックエンドに依存します。 http://blog.ploeh.dk/2012/03/26/IQueryableTisTightCoupling/

これはすべて、バックエンドが提供するLINQのレベルに依存します(NHBrenateはEFより悪化する傾向があり、Mongo、Elastic、Cassandraを使用している場合...誰があなたがAutoMapperを使用するとき、私は壊れます 「LetterContent」すべてのクライアントコードに「コンテンツ」からそのプロパティを変更することを決定した場合は明日

)うまくいかないかもしれないことを知っています。

oDataを使用してエンティティセットにNameプロパティを設定できます。 OdataはデータアクセスレベルがBLではないことを忘れないでください。データベース内のSQL列名を変更するのと同じ方法で扱う必要があります。

関連する問題