2017-05-19 28 views
0

私はジェネリックサービスとリポジトリレイヤがあるプロジェクトで作業しています。 Automapperを使ってDTOをエンティティモデルにマップしています。 1つのエンティティは1つ以上のDTOを持つことができます。私の問題は、どのようにDTOがサービス層に戻さなければならないジェネリックリポジトリクラスに伝えるのですか?単一のエンティティ(Automapper)に複数のDTOを持つ汎用リポジトリ

エンティティ

[Table("Entity")] 
public class Entity 
{ 
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int id { get; set; } 

    [Required] 
    public string name { get; set; } 

    [Required] 
    public string surname { get; set; } 
} 

のDTO

public class Contract 
{ 
} 

[DataContract] 
public class EntityContract: Contract 
{ 
    [Required] 
    [DataMember] 
    public string name { get; set; } 

    [Required] 
    [DataMember] 
    public string surname { get; set; } 
} 

[DataContract] 
public class EntityPassportContract: Contract 
{ 
    [Required] 
    [DataMember] 
    public string name { get; set; } 

    [Required] 
    [DataMember] 
    public string surname { get; set; } 

    [Required] 
    [DataMember] 
    public string passport { get; set; } 
} 

ジェネリックリポジトリ

public interface IGenericRepository<E, DTO> 
    where E : class 
    where DTO: class 
{ 
    List<DTO> findBy(Expression<Func<DTO, bool>> query = null, Func<IQueryable<DTO>, IOrderedQueryable<DTO>> orderBy = null, 
           Expression<Func<DTO, bool>> whereIn = null, int? page = null, int? sizePage = null); 
} 

のGe nericリポジトリの実装

public abstract class GenericRepository<C, E, DTO> : IGenericRepository<T, DTO> 
    where E : class 
    where DTO: class 
    where C : IdentityDbContext<User>, new() 
{ 
    //... 
    public virtual List<DTO> findBy(Expression<Func<DTO, bool>> query = null, Func<IQueryable<DTO>, IOrderedQueryable<DTO>> orderBy = null, 
             Expression<Func<DTO, bool>> whereIn = null, int? page = null, int? sizePage = null) 
    { 
     //...transform DTO queries to E queries and Get IQueriable<E> entity from database 
     DTO dtoEntity=entity.ProjectTo<DTO>(); 
     return dtoEntity;       
    } 
} 

ジェネリックサービス

public interface IService<E, DTO> : IService 
    where T: class 
    where DTO: class 
{ 
    List<DTO> findBy(Expression<Func<DTO, bool>> query = null, Func<IQueryable<DTO>, IOrderedQueryable<DTO>> orderBy = null, 
              Expression<Func<DTO, bool>> whereIn = null, int? page = null, int? sizePage = null); 
} 

一般的なサービスの実装

public abstract class Service<E, DTO> : IService<T, DTO> 
    where E: class 
    where DTO: class 
{ 

    protected IGenericRepository<E, DTO> repository; 
    public Service(IGenericRepository<E, DTO> repository,) 
    { 
     this.repository = repository; 
    } 
    public virtual List<DTO> findBy(Expression<Func<DTO, bool>> query = null, Func<IQueryable<DTO>, IOrderedQueryable<DTO>> orderBy = null, 
               Expression<Func<DTO, bool>> whereIn = null, int? page = null, int? sizePage = null) 
    { 
     return repository.findBy(query, orderBy, whereIn, page, sizePage).ToList(); 
    } 
} 

エンティティリポジトリおよびサービス

public interface IEntityRepository : IGenericRepository<Entity, Contract> 
{ 
} 
public class EntityRepository : GenericRepository<EntitiesDB, Entity, Contract>, IEntityRepository 
{ 
    public EntityRepository(IMapper mapper):base(mapper){ } 
} 

//Service 
public interface IEntityService : IService<Entity, Contract> 
{ 
} 
public class EntityService : Service<Entity, Contract>, IEntityService 
{ 
    private IEntityRepository repo; 

    public EntityService(IEntityRepository repo) : base(repo) 
    { 
     this.repo = repo; 
    } 
} 

コントローラ は、私は一般的なサービスでメソッドfindByを呼び出し、DTOを返すために起こっているかを選択します。契約クラスは私のテストの一部でしたが、動作しません。 サービスの各メソッドをDTOのタイプに渡すことがあるかもしれませんか?

[RoutePrefix("api/entity")] 
public class EntityController : ApiController 
{ 
    public EntityController(IEntityService entityService) 
    : base(entityService) 
    { 
    } 
    [Route("getEntityByFilter", Name = "getEntityByFilter")] 
    [HttpGet] 
    public async Task<IHttpActionResult> getEntityContract(string filter) 
    { 
     EntityContract entityContract=entityService.findBy(**Parameters**); //Need to call lambda expressions here so i think i need somehow the type. 
     return Ok(entityContract); 
    } 
    [Route("getEntityByFilter2", Name = "getEntityByFilter2")] 
    [HttpGet] 
    public async Task<IHttpActionResult> getEntityPassportContract(string filter) 
    { 
     EntityPassportContract entityPassportContract=entityService.findBy(**Parameters**); //Need to call lambda expressions here so i think i need somehow the type. 
     return Ok(entityPassportContract); 
    } 
} 

ありがとうございます!この質問が他の人にも役立つことを願っています!

素晴らしい週末を過ごしましょう!

ルチアーノ

+1

これで、「すべて」を一般的な方法で作成しようとする結果に直面しました。プログラミングはすべてコンテキストに関するもので、まずすべてを分けてから、ある種のジェネリックパターンが見えるときにはジェネリックなアプローチを適用します。 – Fabio

+0

お返事ありがとう@Fabio。私はすでにいくつかの特定のものをやっている特定のリポジトリとサービスを持っています。私はいくつかの簡単なCRUD操作を行うために汎用のものを使用したいと思います。リポジトリごとにfindByを作成すると、エンティティごとに異なる戻り値の型(異なるコントラクト)のコードと同じコードが使用されます。私はそのような状況を避けたい。ありがとう! –

+0

私は、リフレクションなしでこれを行う方法はないと思います。あなたが 'getEntityContract'メソッドでやりたいのであれば、このメソッドはパラメータとして返すタイプについて知っている必要があります。 )、リフレクションを使用して一般的な実行を使用してfindByを実行します。 また、RESTごとにURL名を変更してください。 "api/entity/getEntityByFilter"ではなく "api/entities/byfilter"のように見えます。 別の方法が見つかった場合は、ご意見ください。 – Prince

答えて

0

私の答えが遅れて申し訳ありませんが、とにかく、ここにあります。

これを行う方法は、どのエンティティを返すかを指定する方法でした。だから、私のリポジトリは、私はリポジトリを呼び出す必要があり、だから今この

public abstract class GenericRepository<C, E> : IGenericRepository<T> 
where E : class 
where C : IdentityDbContext<User>, new() 
{ 
    //... 
    public virtual List<DTO> findBy<DTO>(Expression<Func<DTO, bool>> query = 
    null, Func<IQueryable<DTO>, IOrderedQueryable<DTO>> orderBy = null, 
            Expression<Func<DTO, bool>> whereIn = 
     null, int? page = null, int? sizePage = null) 
    { 
     //...transform DTO queries to E queries and Get IQueriable<E> entity 
      from database 
     DTO dtoEntity=entity.ProjectTo<DTO>(); 
     return dtoEntity;       
    } 
} 

のように毎回見て、私は、サービスクラスでこのようにそれを呼び出す:

//If I want the EntityListResumeDTO 
List<EntityListResumeDTO> EntityListContract = repo.findBy<EntityListResumeDTO>(x=>x.id==1); 

//If I want the EntityListCompleteDTO 
List<EntityListCompleteDTO> EntityListContract = repo.findBy<EntityListCompleteDTO>(x=>x.id==1); 

あなたが見ることができるように、DTOはジェネリックタイプはクラスレベルではなく、メソッドレベルにあります。

これは他の人に役立つことを期待しています。より良い解決策があれば教えてください。

乾杯!