你所描述的本身不是問題。這實際上是應用程序設計和模式使用的一個很好的例子。它缺乏的東西使得它看起來有問題,因爲它沒有利用幫助維護性的新技術/新技術。
例如,從您的描述中可以明顯看出,架構明確地將職能職責劃分爲層。您有一個與域(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