【问题标题】:MVC + nHibernate, passing children by id; use DTOs? Wrong approach?MVC + nHibernate,通过 id 传递孩子;使用 DTO?方法错误?
【发布时间】:2012-07-05 22:37:56
【问题描述】:

我正在开发一个三层应用程序(演示、业务、持久性),并且在通过 MVC 与 nHibernate 交互的最佳方法方面遇到了概念上的麻烦。具体来说,我有一个页面可让您创建用户并选择他们的角色。角色下拉列表通过从业务处理程序获得的 List 对象填充。该列表将选定的 ids 保存到一个 int[],a la:

@Html.ListBoxFor(
    x => x.SelectedRoles,
    new SelectList(Model.Roles, "Id", "Name"))

使用这些基类:

public class Role
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<User> Users { get; set; }
}

public class User {
    public virtual int Id { get; set; }
    public virtual string Username { get; set; }
    public virtual IList<Role> Roles { get; set; }
}

public RoleMap()
{
    Id(x => x.Id);
    Map(x => x.Name);

    HasManyToMany(x => x.Users)
        .Table("UserRole")
        .ParentKeyColumn("RoleId")
        .ChildKeyColumn("UserId")
        .Inverse();
}

public UserMap()
{
    Id(x => x.Id);

    Map(x => x.Username);

    HasManyToMany(x => x.Roles)
        .Table("UserRole")
        .ParentKeyColumn("UserId")
        .ChildKeyColumn("RoleId")
        .Cascade.SaveUpdate();
}

然后我使用 AutoMapper 将我的 ViewModel 绑定到我的实体(即 UserCreateViewModel -> User),然后通过 Create(User) 调用将 User 对象传递给其业务处理程序。对于上面的例子,这个工作流崩溃了,因为当我传递一个 User 对象时,它的 List 是空的(因为 AutoMapper 在逻辑上没有将 int[] 绑定到 List)。

这是我的问题出现的地方:

最好将 int[] 传递给我的 Create 方法,即 Create(User, int[]),然后执行User.Roles = ids.Select(x =&gt; _roleRepository.GetById(x)).ToList(); 之类的操作,还是我真的应该使用其他方法...是这是 DTO 发挥作用的地方?我看到他们将来如何使重构更容易,因为我将拥有像 Create(UserDto) 这样的东西,它永远不需要方法重命名(因为我可以根据需要向 DTO 添加更多字段)。

来自基于存储过程的 mini-ORM,我觉得这种方法是错误的。不管使用 DTO,我不会为我通过 GetById 请求的每个角色生成一个新查询吗?或者这是 nHibernate 会自动缓存的东西?

这甚至是正确的方法吗?在过去,我只是将角色 ID 的 int[] 直接传递到 SQL 并从那里创建记录——一个数据库调用来创建用户及其所有角色。很难用一种 ORM 的方式来有效地做到这一点。

【问题讨论】:

    标签: c# asp.net-mvc nhibernate


    【解决方案1】:

    既然您已经在使用AutoMapper,为什么不为Roles 属性创建一个映射?

    .ForMember(x => x.Roles, o => o.MapFrom(
        x => x.Roles.Select(id => _roleRepository.GetById(id)).ToList())
    

    这可以封装在使用 DI 的 AutoMapper 配置文件中:

    public class UserProfile : Profile
    {
        private readonly IRoleRepository _roleRepository;
    
        public UserProfile(IRoleRepository roleRepository)
        {
            _roleRepository = roleRepository;
        }
    
        protected override void Configure()
        {
            CreateMap<UserCreateViewModel, User>()
                .ForMember(x => x.Roles, o => o.MapFrom(
                    x => x.Roles.Select(id => _roleRepository.GetById(id)).ToList());
        }
    }
    

    【讨论】:

    • 不打算这样做,因为无论我将配置文件放在哪里,它们都会引起架构上的麻烦。如果我将它们放在我的业务层中,我必须让该层现在知道我的 ViewModel。如果他们进入演示文稿(我称之为业务处理程序与存储库),我解决了这个问题,但现在我从处理程序中抽象出一段随机逻辑。目前不喜欢这两种方法,认为 DTO 是避免这些事情的方法。
    • 所以我采用了您的解决方案,但在我的 ViewModel 和实体之间插入了一个 DTO,这使我的层保持独立。为 ViweModels -> DTOs 添加了配置文件映射,对于 DTOs -> Entities 也是如此,它可以流畅地工作!谢谢。
    猜你喜欢
    • 2022-10-12
    • 1970-01-01
    • 1970-01-01
    • 2018-05-03
    • 2021-09-06
    • 1970-01-01
    • 1970-01-01
    • 2023-02-14
    • 1970-01-01
    相关资源
    最近更新 更多