【问题标题】:How to properly map entities to domain models in n-tier architecture?如何正确地将实体映射到 n 层架构中的域模型?
【发布时间】:2012-08-20 19:27:41
【问题描述】:

我按照Project Silk's 结构创建了一个中型项目。但是,我无法将我从存储库中检索到的实体映射到域模型对象中以便在 Web 项目中使用。我已经发布了similar question here with all the code 并没有收到我正在寻找的帮助。

我的应用程序的架构非常接近 Project Silk 的架构。数据层包含存储库和模型 POCO。业务逻辑层保存服务。在这些服务中,我们将对象从数据层映射到业务层中的模型对象。

internal static Model.User ToDataModelUser(User userToConvert)
{
    if (userToConvert == null)
    {
        return null;
    }

    Model.User modelUser = new Model.User()
    {
        UserId = userToConvert.UserId,
        AuthorizationId = userToConvert.AuthorizationId,
        DisplayName = userToConvert.DisplayName,
        Country = userToConvert.Country,
        PostalCode = userToConvert.PostalCode,
        HasRegistered = userToConvert.HasRegistered,
    };
    return modelUser;
}

internal static User ToServiceUser(Model.User dataUser)
{
    if (dataUser == null)
    {
        return null;
    }

    User user = new User()
    {
        UserId = dataUser.UserId,
        AuthorizationId = dataUser.AuthorizationId,
        DisplayName = dataUser.DisplayName,
        Country = dataUser.Country,
        PostalCode = dataUser.PostalCode,
        HasRegistered = dataUser.HasRegistered,
    };
    return user;
}

我的问题是,当对象具有多对多关系时,如何映射这样的对象?例如,假设用户有一个 ICollection 角色。这意味着我的角色有一个 ICollection 用户。当我通过 ToDataModelUser 或 ToServiceUser 映射用户时,我现在有一个 Roles 属性要填充。因此,上面的代码将如下所示:

internal static Model.User ToDataModelUser(User userToConvert)
{
    if (userToConvert == null)
    {
        return null;
    }

    Model.User modelUser = new Model.User()
    {
        UserId = userToConvert.UserId,
        AuthorizationId = userToConvert.AuthorizationId,
        DisplayName = userToConvert.DisplayName,
        Country = userToConvert.Country,
        PostalCode = userToConvert.PostalCode,
        HasRegistered = userToConvert.HasRegistered,
        Roles = new Collection<Role>()
    };

    foreach (Role role in userToConvert.Roles)
        modelUser.Roles.Add(RoleServies.ToDataModelRole(role));

    return modelUser;
}

Now here comes the problem, if you look at RoleServices.ToDataModelRole(Role role) this is what you get:

internal static Model.Role ToDataModelRole(Role roleToConvert)
{
    if (roleToConvert == null) return null;

    Model.Role role = new Model.Role()
    {
        Description = roleToConvert.Description,
        RoleId = roleToConvert.RoleId,
        RoleName = roleToConvert.RoleName,
        Users = new Collection<User>()
    };

    foreach (User user in roleToConvert.Users)
        roleToConvert.Users.Add(UserServices.ToDataModelUser(user));

    return role;
}

如您所见,如果您运行此程序,您将收到堆栈溢出错误 b/c,当尝试进行映射时,我们将从用户 >> 角色 >> 用户 >> 角色 >> 等进行。如果我不映射导航属性,我将无法在 Web 项目中访问它们。我有一种感觉,我在这里完全错过了一些东西。

【问题讨论】:

标签: asp.net-mvc entity-framework repository-pattern n-tier-architecture dto


【解决方案1】:

您可以为 ToDataModelX 方法创建重载。传递Boolean 以取消/激活从属对象的加载。不要总是加载角色的用户,而是仅在被指示时加载它们。

internal static Model.User ToDataModelUser(User userToConvert)
{
    return ToDataModelUser(userToConvert, true);
}

internal static Model.User ToDataModelUser(User userToConvert, Boolean loadRoles)
{
    if (userToConvert == null)
    {
        return null;
    }

    Model.User modelUser = new Model.User()
    {
        ....
        Roles = new Collection<Role>()
    };

    if (loadRoles)
    {    
        foreach (Role role in userToConvert.Roles)
            modelUser.Roles.Add(RoleServies.ToDataModelRole(role, false));
    }

    return modelUser;
}


internal static Model.Role ToDataModelRole(Role roleToConvert)
{
    return ToDataModelRole(roleToConvert, true);
}

internal static Model.Role ToDataModelRole(Role roleToConvert, Boolean loadUsers)
{
    if (roleToConvert == null) return null;

    Model.Role role = new Model.Role()
    {
        ....
        Users = new Collection<User>()
    };

    if (loadUsers) 
    {
        foreach (User user in roleToConvert.Users)
            roleToConvert.Users.Add(UserServices.ToDataModelUser(user, false));
    }

    return role;
}

【讨论】:

  • 谢谢,这就是我现在正在做的事情,但是随着我的实体变得越来越复杂并且项目越来越大,我将会有很多重载。我不想为加载角色、加载项目、加载设计审查等加载布尔值。然后我会过载加载角色和项目但不是设计审查等。必须有更清洁的方法吗?
  • 使用可选参数而不是重载。
  • 您可以构建一个“标准”对象,其中包含您要使用的设置。调用可以查看对象的属性并从中做出决定。
  • 再次感谢。从更大的角度来看,我应该放弃这个实体到域的映射,只使用数据库中的实体吗?映射的全部原因是确保我不会无意中暴露或更改数据库。我必须相信这是一种更清洁的整体方法。 TIA
  • 使用映射到/从域对象不是一个坏方法。域对象可以/应该具有比数据库实体更多的逻辑,这些实体服务于与底层数据库交互的严格目的。我相信,使用实体框架,您无法控制定义数据库实体的代码(它是生成的),因此如果数据库结构发生变化并且必须重新生成实体,您可能很难扩展它。但是,这是一个单独的理论/架构主题,不应该在 cmets 中讨论。
猜你喜欢
  • 2015-07-30
  • 2018-02-05
  • 1970-01-01
  • 1970-01-01
  • 2020-06-26
  • 1970-01-01
  • 2015-10-26
  • 2012-05-23
  • 1970-01-01
相关资源
最近更新 更多