你所描述的本身不是问题。这实际上是应用程序设计和模式使用的一个很好的例子。它缺乏的东西使得它看起来有问题,因为它没有利用帮助维护性的新技术/新技术。
例如,从您的描述中可以明显看出,架构明确地将职能职责划分为层。您有一个与域(BLL)进行通信的演示文稿(UI),该域又使用存储库模式与其基础架构(DAL)进行通信。你的BLL似乎已经实施了诸如验证和安全等交叉问题。
你可以做些什么来改进这个设计,那就是通过加入一个模型来包含一个更强的域。删除旧的ADO.NET DataTable技术并设计反映数据库的强类型模型。结合ORM可以极大地帮助它,因为它有能力从数据库生成模型并轻松维护更改。
我不会深入了解ORM的优势。你的DAL应该返回POCO和Enumerables。让BLL返回响应对象(我喜欢称它们为服务响应对象或演示文稿传输对象),其中可能包含如下内容:POCO数据,错误处理结果,验证结果。
另一种可能的解决方案是将您的Repository模式的实现更改为Generic Repository,尽管这会将您的基础架构逻辑放到BLL中。例如,而不是:
public class UserRepository
{
public User GetUserById(Int32 userId){...}
}
您可以创建(使用泛型)实现IQueryable的存储库。看看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企业库验证块。为了支持验证,它使用AutoMapper将Microsoft的验证结果转换为我自己的ValidationResult对象。我不建议尝试序列化MS的类,因为它在服务中使用时很容易出错。
重载的构造函数允许您提供单个poco或pocos的枚举。 POCO vs DataTables ...任何时候你可以使用强类型的对象,它总是更好。使用T4模板,您的POCO可以自动从ORM模型生成。 POCO也可以轻松映射到DTO中进行服务操作,反之亦然。现在也不再需要DataTable了。而不是列表,您可以使用BindingList进行数据绑定的CRUD支持。
返回一个没有填充其所有属性的POCO是非常好的。在实体框架中,这被称为投影。通常我会为此创建自定义的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()));
这应该被标记为社区维基。 – 2011-03-10 18:44:36