【问题标题】:How to implement generic MVC web controllers and generic Views for CRUD operations using EntityFramework如何使用 EntityFramework 为 CRUD 操作实现通用 MVC Web 控制器和通用视图
【发布时间】:2015-09-30 04:07:31
【问题描述】:

我正在设计一个 .NET MVC WEB 应用程序,并确定我必须管理 33 个表(到目前为止)。管理是指典型的 SQL 操作(插入、更新、删除和查询)

这 33 个表中有 16 个是需要使用典型 CRUD 方法处理的引用表。引用表是指被其他表引用并在组合中使用的表(即国家、州、城市、货币等)

我对 .NET 中的 MVC 非常陌生,但已经看到,当您使用脚手架时,您会得到具有典型方法的控制器:

  • 索引(获取)
  • 详细信息(获取)
  • 创建(获取 + 发布)
  • 编辑(获取 + 发布)
  • 删除(获取 + 发布)

另外在数据库方面,我计划使用使用 EntityFramework 实现 INSERT、UPDATE、DELETE 和 LIST(查询操作)的典型 DAO

这是我的问题(最后 ;-)

由于我 50% 的表将以相同的方式在视觉和功能上进行管理,并提供相同的 CRUD 操作我可以使用一种模式或方法来实现最佳的代码/视图重用吗?强>。

我要避免的是搭建 16 个实体来获得 16 个控制器,每个控制器具有 16*5 视图(创建、删除、详细信息、编辑和索引)

是否有可能有一个Single Main controller 可以路由或管理所有这 16 个实体并调用实体所需的操作?

是否有可能拥有一组足够通用的视图(创建、删除、详细信息、编辑和索引)来处理相同的 16 个实体?

如果以上两个是可能的,我将如何在 Web 项目的配置中连接路由以仍然能够为这 16 个实体中的每一个实体(/Countries/Edit/5,/ States/Edit/5 等等)?

这是我认为可以实现这一目标的一种方法:

  • 为所有这 16 个实体拥有一个抽象/公共基类或接口,以及管理 EntityFramework 上下文(即 IManageData)的 Save、GetAll 和 Delete 数据库操作的逻辑
  • 有一个 EntityDao,它使用 EntityFramework 调用已实现 IManageData 并执行操作的任何类的方法。
  • 拥有一个 Abstract/Common 基类(Web 控制器),其中包含所有 16 个可以调用 IManageData 方法的实体的 CRUD 操作的通用逻辑

请帮助我验证/完成我的设计草案,并提出一些注意事项或更好的方法来实现这一点。

这里只是提供一些上下文是一个链接,用于使用 MVC 项目 https://code.msdn.microsoft.com/MVC5-Demo-with-Entity-c6bc81df 搭建 EntitieFramework 实体的方法

这是一个非常相似的问题,有一个已接受的答案,我想在决定如何实现之前对其进行验证。

Generic CRUD controllers and views

【问题讨论】:

  • msdn.microsoft.com/en-US/data/ee712907#codefirst。希望它对您的问题也有帮助。
  • @mybirthname 我已经提供了足够的细节来尝试缩小范围,并确保有“通用管理员”方法的特定实现。我希望它不会被关闭
  • 我个人不喜欢在您的链接中接受的答案,因为该解决方案中的 Web 代码和数据代码紧密耦合
  • @Disappointed 那你会怎么做呢?

标签: c# asp.net-mvc entity-framework


【解决方案1】:

我在之前的项目中也遇到过类似的情况。我是这样做的。这是每个实体(表)的通用接口

public interface IRepository<T>
{
    void Add(T entity, User initiator);
    void Update(T entity, User initiator);
    void Delete(T entity);
    void Delete(int entityId);
    IEnumerable<T> GetAll();
    T GetById(int entityId);
}

这个通用数据层可以很容易地使用实体框架(代码示例,例如底部的here )或使用不同的方法(如我的例子中的存储过程)来实现

我实际上没有任何额外的业务逻辑,所以我的 Web 项目可以直接访问数据存储库。所以它是我的通用基础控制器

public abstract class BaseController<T, M> : Controller
    where M : new()
{
    public BaseController(IRepository<T> repository)
    {
        this._repository = repository;
        ViewBag.CurrentUser = CurrentUser;
    }

    protected User CurrentUser
    {
        get
        {
            if (System.Web.HttpContext.Current.User.Identity.IsAuthenticated)
            {
                return Mapper.Map<User>(System.Web.HttpContext.Current.User.Identity);
            }
            return null;
        }
    }

    protected virtual int PageSize
    {
        get { return 5; }
    }

    protected IRepository<T> _repository;

    public virtual ActionResult Index(int? currentPage)
    {
        var entities = _repository.GetAll();
        List<M> model = new List<M>();

        foreach (var currentEntity in entities)
        {
            model.Add(Mapper.Map<M>(currentEntity));
        }

        int pageNumber = (currentPage ?? 1);
        return View(model.ToPagedList(pageNumber, PageSize));
    }

    [HttpGet]
    public virtual ActionResult Add()
    {
        return View(new M());
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    [ValidateInput(false)]
    public virtual ActionResult Add(M model)
    {
        if (ModelState.IsValid)
        {
            _repository.Add(Mapper.Map<T>(model), CurrentUser);
            return RedirectToAction("Index");
        }

        return View(model);
    }

    [HttpGet]
    public virtual ActionResult Update(int modelId)
    {
        T domainModelEntity = _repository.GetById(modelId);
        M model = Mapper.Map<M>(domainModelEntity);

        return View(model);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    [ValidateInput(false)]
    public virtual ActionResult Update(M model)
    {
        if (ModelState.IsValid)
        {
            _repository.Update(Mapper.Map<T>(model), CurrentUser);
            return RedirectToAction("Index");
        }

        return View(model);
    }

    public virtual ActionResult Delete(int modelId)
    {
        _repository.Delete(modelId);
        return RedirectToAction("Index");
    }
}

还有这个特定的控制器

public class WebPagesController : BaseWebEntityController<WebPage, WebPageModel>
{
    public WebPagesController(IRepository<WebPage> repository)
        : base(repository)
    {
    }
}

稍微解释一下。 a)您应该使用一些 IOC 来解决控制器依赖关系。b)T 用于数据库(表)中的实体,M 用于返回给 View.c 的模型) Automapper 是众所周知的库。
我没有对路由进行任何更改。将其保留为默认值。
希望能帮助到你。祝你好运。

【讨论】:

  • 嗨,我有一个问题,我想从我的泛型类中获取表: public virtual TEntity GetById(int id) { return _db.Set().FirstOrDefault(c => ( (IEntity)c).Code == id);但是 Linq 不能转换 IEntity public abstract class BaseRepository : IRepository where TEntity : class where M : new() 如果用“TEntity : IEntity”替换“TEntity : class”我有这个错误:类型“TEntity”必须是引用类型才能将其用作泛型类型或方法“System.Data.Entity.DbContext.Set() 中的参数“TEntity”你能帮帮我吗?谢谢
猜你喜欢
  • 2015-01-17
  • 1970-01-01
  • 2016-08-03
  • 1970-01-01
  • 2016-06-23
  • 2018-11-08
  • 2011-05-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多