당신이 묘사 한 내용은 그 자체로 문제가 아닙니다. 사실 응용 프로그램 디자인 및 패턴 사용의 좋은 예입니다. 문제가있는 것처럼 보이지 않는 것은 유지 보수성을 돕는 새로운 기술/기법을 활용하지 않는다는 것입니다.
예를 들어, 설명을 통해 구조가 기능적 책임을 계층으로 분명히 구분한다는 것은 명백합니다.도메인 (BLL)과 통신하는 프리젠 테이션 (UI)은 리포지토리 패턴을 사용하여 해당 인프라 (DAL)와 통신합니다. 귀하의 BLL은 이미 유효성 확인 및 보안과 같은 교차 관심사를 구현 한 것 같습니다.
이 디자인을 개선하기 위해 수행 할 수있는 작업은 모델을 포함시켜 더 강력한 도메인을 통합하는 것입니다. 이전 ADO.NET DataTable 기술을 삭제하고 데이터베이스를 반영하는 강력한 형식의 모델을 디자인하십시오. ORM을 통합하면 데이터베이스에서 모델을 생성하고 변경 사항을 쉽게 유지할 수있는 힘이 있으므로 엄청난 도움이됩니다.
원하는 ORM 이점을 얻지는 않겠습니다. DAL은 POCO 및 Enumerables를 반환해야합니다. 당신의 BLL이 POCO 데이터, 오류 처리 결과, 유효성 검사 결과 등을 포함 할 수있는 응답 객체를 반환하도록하십시오 (서비스 응답 객체 또는 프리젠 테이션 전송 객체라고 부릅니다).
또 다른 가능한 해결책은 리포지토리 패턴 구현을 일반 리포지토리로 변경하는 것입니다.이 방법은 인프라 논리를 BLL로 유출시킵니다. 예를 들어, 다음 대신에 :
public class UserRepository
{
public User GetUserById(Int32 userId){...}
}
IQueryable을 구현하는 저장소를 만들 수 있습니다 (generics 사용). 이것에 대한 좋은 접근 방법은 nCommon을보십시오. 이렇게하면 다음과 같은 작업을 수행 할 수 있습니다.
var userRepository = new EF4Repository<User>(OrmContextFactory.CreateContext(...));
User u = userRepository.Where(user => user.Id == 1).SingleOrDefault();
이점은 도메인 비즈니스 로직을 작성하기 만하면된다는 것입니다. 데이터베이스 테이블을 수정해야하는 경우 비즈니스 로직을 한 번만 변경하면됩니다. 그러나이 쿼리는 비즈니스 로직에 존재하며 "리포지토리"를 매체로 사용하여 일부는 부적절하다고 판단되는 데이터베이스와 통신합니다.
당신은 간단한 응답 객체를 생성하기위한 제네릭을 사용할 수 있습니다
UPDATE. 예 :
[DataContract(Name = "ServiceResponseOf{0}")]
public class ServiceResponse<TDto> : ResponseTransferObjectBase<TDto> where TDto : IDto
{
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ServiceResponse<TDto>"/> class.
/// </summary>
/// <param name="error">The error.</param>
/// <remarks></remarks>
public ServiceResponse(ServiceErrorBase error)
: this(ResponseStatus.Failure, null, new List<ServiceErrorBase> {error}, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ServiceResponse<TDto>"/> class.
/// </summary>
/// <param name="errors">The errors.</param>
/// <remarks></remarks>
public ServiceResponse(IEnumerable<ServiceErrorBase> errors)
: this(ResponseStatus.Failure, null, errors, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ServiceResponse<TDto>"/> class with a status of <see cref="ResponseStatus.Failure"/>.
/// </summary>
/// <param name="validationResults">The validation results.</param>
public ServiceResponse(MSValidation.ValidationResults validationResults)
: this(ResponseStatus.Failure, null, null, validationResults)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ServiceResponse<TDto>"/> class with a status of <see cref="ResponseStatus.Success"/>.
/// </summary>
/// <param name="data">The response data.</param>
public ServiceResponse(TDto data)
: this(ResponseStatus.Success, new List<TDto> { data }, null, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ServiceResponse<TDto>"/> class with a status of <see cref="ResponseStatus.Success"/>.
/// </summary>
/// <param name="data">The response data.</param>
public ServiceResponse(IEnumerable<TDto> data)
: this(ResponseStatus.Success, data, null, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ServiceResponse<TDto>"/> class.
/// </summary>
/// <param name="responseStatus">The response status.</param>
/// <param name="data">The data.</param>
/// <param name="errors">The errors.</param>
/// <param name="validationResults">The validation results.</param>
/// <remarks></remarks>
private ServiceResponse(ResponseStatus responseStatus, IEnumerable<TDto> data, IEnumerable<ServiceErrorBase> errors, MSValidation.ValidationResults validationResults)
{
Status = responseStatus;
Data = (data != null) ? new List<TDto>(data) : new List<TDto>();
Errors = Mapper.Map<IEnumerable<ServiceErrorBase>, List<ServiceError>>(errors) ??
new List<ServiceError>();
ValidationResults =
Mapper.Map<MSValidation.ValidationResults, List<IValidationResult>>(validationResults) ??
new List<IValidationResult>();
}
#endregion
#region Properties
/// <summary>
/// Gets the <see cref="IDto"/> data.
/// </summary>
[DataMember(Order = 0)]
public List<TDto> Data { get; private set; }
[DataMember(Order = 1)]
public List<ServiceError> Errors { get; private set; }
/// <summary>
/// Gets the <see cref="ValidationResults"/> validation results.
/// </summary>
[DataMember(Order = 2)]
public List<IValidationResult> ValidationResults { get; private set; }
/// <summary>
/// Gets the <see cref="ResponseStatus"/> indicating whether the request failed or succeeded.
/// </summary>
[DataMember(Order = 3)]
public ResponseStatus Status { get; private set; }
#endregion
}
이 클래스는 내 도메인의 결과를 내 서비스 계층 또는 내 프레젠테이션으로 반환하는 데 사용하는 기본 응답 개체입니다. 직렬화가 가능하며 MS Enterprise Library Validation Block을 지원합니다. 유효성 검사를 지원하기 위해 AutoMapper를 사용하여 Microsoft의 유효성 검사 결과를 내 자신의 ValidationResult 객체로 변환합니다. 서비스에서 사용할 때 오류가 발생하기 쉽기 때문에 MS 클래스를 직렬화하려고하지 않는 것이 좋습니다.
오버로드 된 생성자를 사용하면 단일 poco 또는 pocos를 열거 할 수 있습니다. POCOs 대 DataTables ... 항상 강력하게 형식화 된 객체를 사용할 수 있으므로 언제나 좋습니다. T4 템플릿으로 POCO가 자동으로 ORM 모델에서 생성 될 수 있습니다. POCO는 서비스 운영을 위해 DTO에 쉽게 매핑 될 수 있으며 그 반대도 마찬가지입니다. 더 이상 DataTables에 대한 실질적인 필요성이 없습니다. List 대신에 데이터 바인딩과 함께 CRUD 지원을 위해 BindingList를 사용할 수 있습니다.
모든 속성을 채우지 않은 상태로 POCO를 반환하면 문제가 없습니다. Entity Framework에서는이를 프로젝션이라고합니다. 보통 도메인 엔티티가 아닌 사용자 정의 DTO를 만듭니다.
UPDATE
예에 ValidationResult 클래스 : 마이크로 소프트 확인을 변환하는
/// <summary>
/// Represents results returned from Microsoft Enterprise Library Validation. See <see cref="MSValidation.ValidationResult"/>.
/// </summary>
[DataContract]
public sealed class ValidationResult : IValidationResult
{
[DataMember(Order = 0)]
public String Key { get; private set; }
[DataMember(Order = 1)]
public String Message { get; private set; }
[DataMember(Order = 3)]
public List<IValidationResult> NestedValidationResults { get; private set; }
[DataMember(Order = 2)]
public Type TargetType { get; private set; }
public ValidationResult(String key, String message, Type targetType, List<ValidationResult> nestedValidationResults)
{
Key = key;
Message = message;
NestedValidationResults = new List<IValidationResult>(nestedValidationResults);
TargetType = targetType;
}
}
예 AutoMapper 코드는에 ValidationResult DTO에 결과 :
Mapper.CreateMap<MSValidation.ValidationResult, IValidationResult>().ConstructUsing(
dest =>
new ValidationResult(
dest.Key,
dest.Message,
dest.Target.GetType(),
dest.NestedValidationResults.Select(mappingManager.Map<MSValidation.ValidationResult, ValidationResult>).ToList()));
이것은 커뮤니티 위키로 표시되어야한다. –