【问题标题】:How to map Entity Framework model classes with Business Layer class in n-tier architecture - ASP.NET-MVC如何在 n 层架构中将实体框架模型类与业务层类映射 - ASP.NET-MVC
【发布时间】:2015-07-30 22:11:26
【问题描述】:

我正在研究 MVC 框架(ASP.NET MVC5、Entity Framework 6)中的 e-tier 架构。我的应用程序分为三个子项目,它们是业务层、数据访问层、存储库(包括存储库和工作单元)和 ASP.NET MVC Web 应用程序。我正在努力理解业务数据和实体框架模型之间的映射。例如,如果我在实体框架中有模型类 User 作为

DAL - 用户模型

[Table("User")]
public class User
{
    public User() { }

    [Key]
    public int UserID { get; set; }

    [StringLength(250)]
    [Required]
    public string FirstName { get; set; }

    [StringLength(250)]
    [Required]
    public string LastName { get; set; }

    [Required]
    public int Age { get; set; }

    [StringLength(250)]
    [Required]
    public string EmailAddress { get; set; }

    public ICollection<UserInGroup> UserInGroup { get; set; }
}

在业务层我有用户类

BLL - 用户类

public class User
{
    private string userID;
    private string firstName;
    private string lastName; 
    private int age;
    private string emailAddress;


    public string UserID
    {
        get { return userID; }
        set { userID = value; }
    }

    public string FirstName
    {
        get { return firstName; }
        set { firstName = value; }
    }

    public string LastName
    {
        get { return lastName; }
        set { lastName = value; }
    }

    public int Age
    {
        get { return age; }
        set { age = value; }
    }

    public string EmailAddress
    {
        get { return emailAddress; }
        set { emailAddress = value; }
    }

    public void GetAllUser()
    {
        List<App.DAL.Model.User> _user = new List<DAL.Model.User>();

        using (var _uow = new UserManagement_UnitOfWork())
        {

            _user = (from u in _uow.User_Repository.GetAll()
                     select u).ToList();

        }           
    }
}

我如何一起映射;其次;参考 GetAllUser() 方法,我仍然需要使用 DAL 中的 User 模型类才能从数据库中获取所有用户,我目前的理解是;每一层都应该相互独立,我有抽象层,即数据访问层和业务层之间的存储库。我对这两个概念一起工作感到有些困惑。我是在正确的轨道上还是错过了什么。还需要用户业务层的实际答案。

【问题讨论】:

  • 如果没有要添加的内容,为什么不直接使用原始类?此外,GetAllUser() 应该是静态的或其他位置,因为用户对象没有必要返回所有用户。
  • 首先:当然层不是独立的——过去的想法是层-n 只知道层-(n-1)(或下面的所有层)——无论如何架构取决于你的用例的大小——当你只是做一个 TODO 列表时,把所有东西都抽象出来是多余的。话虽如此:DAL 和 BLL 都应该知道您的模型 - 这样您的 Repositories 可以与 BLL 将使用的实际模型一起使用(这就是我将如何实现它)

标签: c# asp.net-mvc asp.net-mvc-5 repository-pattern n-tier-architecture


【解决方案1】:

您的问题更多是关于没有“一刀切”解决方案的设计/架构。我最多可以分享一些建议以及我通常在相当典型的 ASP.NET MVC + Entity Framework 堆栈中会做什么:

1。确保您的 BLL.User 类遵守 Single Responsibility Principle

您的BLL.User 类不应关注如何通过实体框架/工作单元从数据库中检索DAL.User。您应该简单地拥有另一个负责该任务的类/层:

public interface IUserRepository
{
    IEnumerable<User> GetAllUsers();
}

然后另一个类来实现IUserRepository

public class UserRepository : IUserRepository
{
    private readonly UserManagement_UnitOfWork _unitOfWork;

    public UserRepository(UserManagement_UnitOfWork unitOfWork)
    {
         _unitOfWork = unitOfWork;
    }

    public IEnumerable<User> GetAllUsers()
    {
        return from u in _unitOfWork.User_Repository.GetAll()
               select u;
    }
}

这样做可以消除您的 BLL.UserUserManagment_UnitOfWork 类的依赖,并促进测试/模拟(即可以编写单元测试来模拟内存中的 IUserRepository

然后从您的控制器中,每当需要检索BLL.Users 时,您只需将IUserRepository 的实例注入控制器的构造函数即可:

public class UserController
{
    private readonly IUserRepository _userRepository;

    public UserController(IUserRepository userRepository)
    {
         _userRepository = userRepository;
    }

    public ActionResult Index()
    {
        // Simple example using IEnumerable<BLL.User> as the view model
        return View(_userRepository.GetAllUsers().ToList());
    }
}

2。如何将DAL.User 映射到BLL.User

它实际上与第 1 点非常相似,您可以简单地拥有另一个接口/类对:

public interface IUserMapper
{
     BLL.User MapUser(DAL.User);
}

public class UserMapper : IUserMapper
{
    public BLL.User MapUser(DAL.User user)
    {
         return new BLL.User
         {
             FirstName = user.FirstName,
             LastName = user.LastName,
             Age = user.Age
             // etc...
         };
    }
}

或者,如果您认为编写映射代码很乏味,请考虑使用AutoMapper,以便您的代码变为Mapper.Map&lt;DAL.User, BLL.User&gt;(user)

奖励积分

  1. 您可以跳过BLL.User 中的那些private 字段并将它们转换为自动属性
  2. 您可以添加派生自 ValidationAttribute 的属性以帮助在您的 ASP.NET MVC 应用程序中进行验证
public class User
{
    public string UserId { get; set; }

    [Required]
    public string FirstName { get; set; }

    public string LastName { get; set; }

    [Range(0, int.MaxValue)]
    public int Age { get; set; }

    [EmailAddress]
    public string EmailAddress { get; set; }
}

【讨论】:

    【解决方案2】:

    首先,不需要存储库层和数据访问层。这 2 层具有相同的目的 - 添加一个抽象层来处理您的持久存储。虽然他们有不同的概念

    1. 存储库模式基本上为您提供了一种使用数据库的方法,就好像它是内存中的集合一样。大多数情况下,它公开了基本的 CRUD(创建读取更新和删除)方法以及一些其他扩展,例如 GetAll 方法等。这是一个非常简化的描述,但是关于此模式有足够的资源 for example
    2. 数据访问层还添加了抽象,但以更加主观的方式。基本上它包含用于访问数据库的所有 API。例如,对于您的 User 类,它可能具有 GetUserByNameGetUserByIdRemoveUserGetAllActiveUsers 等方法。

    此外,工作单元也不必在存储库/DAL 中实现。由于单个工作单元可以包含多个实体的修改或对外部服务的请求。我认为 BLL 更适合 UoW,因为在大多数情况下,您可以将单个业务操作(BL 中的一种方法)视为 UoW

    现在这有点清楚了(希望)。您的存储库/DAL 应该只返回业务实体而不是数据库生成的类(如果它们不同),并且所有映射逻辑都应该封装在存储库/DAL 层中。例如,GetUserById 方法应该返回一个BLL - User Class,而不是在这种情况下由 EF 生成的用户类,它可以是存储库/DAL 层的内部类。

    为了处理这些类之间的映射,您可以使用不同的库,例如 ValueInjecterAutoMapper,它们非常棒,可以让您的开发更加轻松。

    【讨论】:

      【解决方案3】:

      您只需使用AutoMapper 即可完成此操作 通过 Nuget 安装:

      PM> Install-Package AutoMapper
      

      然后您所要做的就是配置 AutoMapper 为您映射类似的对象。

      Mapper.CreateMap<DAL.User, BLL.User>();
      

      您可以像这样在任何地方转换对象:

      BLL.User bll_User = Mapper.Map<DAL.User, BLL.User>(dal_user);
      

      【讨论】:

        猜你喜欢
        • 2023-03-27
        • 1970-01-01
        • 1970-01-01
        • 2012-03-04
        • 2010-10-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多