MVC BaseController handling CRUD operations

2019-05-06 06:09发布

问题:

I want to refactor my basic CRUD operations as they are very repetitive but I'm not sure the best way to go about it. All of my controllers inherit BaseController which looks like so:

public class BaseController<T> : Controller where T : EntityObject
{
    protected Repository<T> Repository;

    public BaseController()
    {
        Repository = new Repository<T>(new Models.DatabaseContextContainer());
    }

    public virtual ActionResult Index()
    {
        return View(Repository.Get());
    }
}

I create new controllers like so:

public class ForumController : BaseController<Forum> { }

Nice and easy and as you can see my BaseController contains an Index() method so that means my controllers all have an Index method and will load their respective views and data from the repository - this works perfectly. I'm struggling on Edit/Add/Delete methods, my Add method in my repository looks like this:

public T Add(T Entity)
{
    Table.AddObject(Entity);
    SaveChanges();

    return Entity;
}

Again, nice and easy but in my BaseController I obviously can't do:

public ActionResult Create(Category Category)
{
    Repository.Add(Category);
    return RedirectToAction("View", "Category", new { id = Category.Id });
}

as I usually would so: any ideas? My brain can't seem to get pass this.. ;-/

回答1:

You could add an interface shared by all entities:

public interface IEntity
{
    long ID { get; set; }
}

And make your base controller require this:

public class BaseController<T> : Controller where T : class, IEntity

Which would allow you to:

public ActionResult Create(T entity)
{
    Repository.Add(entity);
    return RedirectToAction("View", typeof(T).Name, new { ID = entity.ID });
}

You should also consider using dependency injection to instantiate your controllers, so that your repositories are injected rather than instantiated manually, but that is a separate topic.



回答2:

Not sure what the problem is, you can't make the CRUD points to be generic as well?

public virtual ActionResult Create(T entity) where T : IEntity
{
    Repository.Add(entity);
    return RedirectToAction("View", this.ModelType, new { id = entity.Id });
}

This assumes that:

  • Your controllers set a value called "ModelType" on the base controller when they are constructed, which tells it what 'kind' of models it's supposed to be controlling.
  • You have a common interface (IEntity) or known base class which has a set of basic properties (like Id) which can be used by the controller to manage flow parameters and so on.

I haven't actually tried this but I've done scaffolding similar to it and the pattern works well enough. It might be sticky if it's not possible to modify or extend your POCO (or whatever you're using) object model.