2

我正在做一个大型项目,其中一部分是要替换现有的服务器堆栈。对于一个非常规范化的大型数据库,很明显我们需要构造许多复合对象。我的一个查询示例如下:我的复合对象定义:

[DataContract]
public class CompositeEvent
{
    Guid eventIdentity;
    string accountIdentity;
    string eventMessage;
    DateTime eventLoggedOn;
    string methodName;
    string programName;
    string userIdentity;
    List<CompositeException> exceptions = new List<CompositeException>( );
    List<CompositeParameter> methodParameters = new List<CompositeParameter>( );
    List<CompositeParameter> databaseParameters = new List<CompositeParameter>( );

    [DataMember]
    public Guid EventIdentity
    {
        get { return eventIdentity; }
        set { eventIdentity = value; }
    }
    [DataMember]
    public string AccountIdentity
    {
        get { return accountIdentity; }
        set { accountIdentity = value; }
    }
    [DataMember]
    public string EventMessage
    {
        get { return eventMessage; }
        set { eventMessage = value; }
    }

    [DataMember]
    public DateTime EventLoggedOn
    {
        get { return eventLoggedOn; }
        set { eventLoggedOn = value; }
    }

    [DataMember]
    public string MethodName
    {
        get { return methodName; }
        set { methodName = value; }
    }

    [DataMember]
    public string ProgramName
    {
        get { return programName; }
        set { programName = value; }
    }

    [DataMember]
    public string UserIdentity
    {
        get { return userIdentity; }
        set { userIdentity = value; }
    }

    public string QualifiedCreator
    {
        get 
        {
            if ( String.IsNullOrEmpty( programName ) && String.IsNullOrEmpty( methodName ) )
                return string.Empty;
            return string.Format( "{0}:{1}", String.IsNullOrEmpty( ProgramName ) ? "{undefined}" : ProgramName, String.IsNullOrEmpty( MethodName ) ? "{undefined}" : MethodName );
        }
    }
    [DataMember]
    public int EventTypeIdentity { get; set; }

    [DataMember]
    public string EventTypeName { get; set; }

    [DataMember]
    public List<CompositeException> Exceptions
    {
        get { return exceptions; }
        set { exceptions = value; }
    }

    [DataMember]
    public List<CompositeParameter> MethodParameters
    {
        get { return methodParameters; }
        set { methodParameters = value; }
    }

    [DataMember]
    public List<CompositeParameter> DatabaseParameters
    {
        get { return databaseParameters; }
        set { databaseParameters = value; }
    }
}

我的服务中的数据库查询:

            using ( Framework.Data.FrameworkDataEntities context = new Data.FrameworkDataEntities( ) )
        {
            var list = from item in context.EventLogs
                       join typeName in context.EventLogTypes on item.EventTypeId equals typeName.Id
                       orderby item.EventLoggedOn, item.EventLogType
                       select new CompositeEvent
                       {
                           AccountIdentity = item.AccountIdentity,
                           EventIdentity = item.Id,
                           EventLoggedOn = item.EventLoggedOn,
                           EventMessage = item.EventMessage,
                           EventTypeIdentity = item.EventTypeId,
                           EventTypeName = typeName.EventTypeName,
                           MethodName = item.MethodName,
                           ProgramName = item.ProgramName,
                           UserIdentity = item.UserIdentity
                       };
            return new List<CompositeEvent>( list );
        }

现在从我的复合对象的定义中可以清楚地看出,它只包含数据,没有业务规则,也没有其他持久性或业务结构、数据结构或其他任何东西的暴露。

然而我的队友说这只能存在于域模型中,我必须花费周期将我的数据从这个定义明确的对象移动到 DTO。不仅如此,a) 所有 DTO 的名称中都必须包含 DTO,并且 b) 它们的存在必须仅用于在网络中移动的目的。因此,当我们的客户端代码被开发时,它必须 a)创建每个对象属性的属性,并且 b)从 DTO 移动到视图模型属性。

我觉得这把DTO推到了极致。即基于这些 ARE 数据传输对象的复合对象的定义。此外,我认为将此对象存储在客户端并直接绑定到客户端中的此对象绝对没有问题。由于我所做的只是获取复合对象中定义的每个属性并将它们复制到 DTO 中,因此创建一个对象只是为了将其复制到另一个对象然后再次将其复制到内部似乎是浪费大量时间和周期客户端的属性。

我对这方面的其他意见感兴趣。我觉得我没有违反任何 OOP 规则,例如关注点分离或单一责任原则……至少只要您不对这些感到极度敏感。意见???

4

1 回答 1

2

好吧,MUST你同事强调的一切让他看起来有点强迫症。但这没关系,因为他确实有道理。

DTO,尤其是在 MVC 中,应该以抽象底层数据模型的方式设计,因此它们成为视图的实际模型。让它们靠近您的对象只会导致您修改两组对象,而实际上可能只有其中一个对象需要更改。

在 SoA 或 N 层架构中设计 DTO 时要考虑的另一件事是,它们不应在视图层与底层服务和模型之间创建契约。因此,如果您的数据库(字段、表、视图等)发生了某些变化,您应该能够调整服务层的所有内容,并以不影响 DTO 的方式降低。

视图模型应该保持不变,至少只要您不向其中添加或删除功能。任何潜在的变化都应该适应 DTO(不是这样——但并不总是可能的)。

现在我应该提一下,我现在正在将项目从 SoA 和 DTO 切换到普通的 2 层架构(这是因为性能问题,而不是 DTO :))。我有一个简单和复杂对象的跨领域域层,旨在仅在内部使用。任何通过 Web 服务公开的 API 都将使用 DTO,因为我不想杀死 WS 消费者。也许会伤害他们一点:)。

但是你应该使用 DTO,就像我上面提到的那样。它将在您的情况下有所帮助(使用 MVC)。为了更轻松地映射到 DTO,我建议反之亦然AutoMapper。会让你的生活更轻松(让你的同事开心)。

于 2012-07-05T19:50:17.293 回答