2017-05-19 28 views
0

我在一個項目中工作,我有一個通用服務和存儲庫層。我使用Automapper將DTO映射到實體模型。一個實體可以有一個或多個DTO。我的問題是,如何告訴我的通用存儲庫類,哪個DTO應該返回到服務層?具有多個DTO到一個實體的通用存儲庫(Automapper)

實體

[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); 
} 

戈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); 
    } 
} 

非常感謝!我希望這個問題也能幫助其他人!

週末愉快!

Luciano

+1

現在你面臨着試圖以通用方式製造「一切」的後果。編程是關於上下文的,你首先分離一切,然後當你看到一些通用模式時,你將使用通用的方法。 – Fabio

+0

感謝@Fabio爲您解答。我已經有了一些特定的存儲庫和服務來做一些特定的事情。我想用通用的做一些簡單的CRUD操作。如果我爲每個存儲庫構建一個findBy,我將爲每個實體使用完全相同的代碼,但具有不同的返回類型(不同的合同)。我想避免這種情況。謝謝! –

+0

我不認爲如果你想在一個方法'getEntityContract'中做一個這樣做的方法,那麼這個方法應該知道返回的類型,無論是作爲參數還是頭部(無論你感覺如何),然後使用反射來執行使用通用執行的findBy。 也請改變URL名稱,就像每個REST一樣,URL應該看起來像「api/entities/byfilter」而不是「api/entity/getEntityByFilter」 如果你找到其他方法,請評論。 – 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通用類型不再是課堂級別,而是在方法級別。

希望這可以幫助其他人,如果你有更好的解決方案,請讓我知道。

乾杯!

相關問題