【问题标题】:ASP.NET MVC 5 Common actions for more controllersASP.NET MVC 5 更多控制器的常用操作
【发布时间】:2014-03-12 02:59:49
【问题描述】:

我有一些控制器(并且会更多),它们共享一些类似的操作:

public ActionResult DeleteConfirmed(int id)
{
    Supplier s = db.Suppliers.Find(id);
    s.Deleted = true;
    db.SaveChanges();
    return RedirectToAction("Index");
}

public ActionResult RestoreConfirmed(int id)
{
    Supplier s = db.Suppliers.Find(id);
    s.Deleted = false;
    db.SaveChanges();
    return RedirectToAction("Index");
}

这些操作是SuppliersController 的一部分。这样做的目的是,当我删除或恢复一个对象时,它会将数据库中的对象标记为已删除字段的真(恢复时为假)。

CurrenciesControllerProductsController 等许多其他控制器共享相同的行为...

在我展示的代码中,您应该看到明确指定了我的数据库实体 (Supplier) 以及存储库 (Suppliers)。

我想找到一种通用的方法。我想创建一个自定义控制器,并且所有其他具有相同行为的控制器都将对其进行扩展。在这种情况下,ProductsController 将扩展我的 DeleteRestoreController

我怎样才能以“通用”的方式做到这一点?

dbDbContext

public partial class LE: DbContext
{
public LE()
    : base("name=LE")
{
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    throw new UnintentionalCodeFirstException();
}

public virtual DbSet<Category> Categories { get; set; }
public virtual DbSet<CategoryText> CategoryTexts { get; set; }
...
}

Categories 也有相同的行为。

【问题讨论】:

  • 什么是db?那是一个 Repository 对象,还是一个 DataContext?如果它是 DataContext,则您的代码已经尽可能优化。如果您在控制器后面使用 Repository 对象,只需将前三行代码重构为 Repository 方法,然后调用它。
  • @RobertHarvey 帖子已更新
  • 我们讨论了多少这样的实例?除非你有 20 个或更多,否则我认为不值得麻烦,甚至可能不值得。
  • 现在我还没有 20 个,但我预计会有很多。也是可以减少的冗余代码。
  • 那么它不仅仅是一个供应商吗?如果你将它推回存储库方法,你只会得到一个包含所有实体的大 case 语句,除非你有一个 generic repository。所以你所做的只是将复杂性推到其他地方(尽管你正在让你的模型更胖而你的控制器更瘦)。

标签: asp.net asp.net-mvc controller


【解决方案1】:

更进一步

public abstract class DeleteRestoreController<T> : Controller
{

public virtual Action DeleteConfirmed(int id)
{
    var dbset = db.Set<T>();

    var s = dbset.Find(id);
    s.Deleted = true;
    db.SaveChanges();
    return RedirectToAction("Index");
}
}

然后在定义控制器时添加实体类型

public class ProductsController : DeleteRestoreController<Supplier>
{
////blah
}

【讨论】:

  • 您还可以添加一个抽象层,例如存储库模式。我有一个 UnitOfWork 类,它有一个方法 public IRepository GetRepository() where T : BaseEntity 我可以调用它,并为我提供的任何实体提供一个通用存储库。我的 UnitOfWork 还具有几个特定存储库的属性,这些存储库执行通用存储库之外的操作。
  • 这是我正在寻找的解决方案或类似的解决方案。谢谢!
  • 另外,第二个想法似乎比您发布的解决方案更好,但更多可能有助于理解。
  • 但也有两个问题。在设置 dbset 时,我需要对 的引用,并且此上下文中不存在 Deleted 属性。在这里我不知道该怎么办
【解决方案2】:

您可以将DeleteRestoreController 实现为抽象类。

public abstract class DeleteRestoreController : Controller
{
    private IRepository : Repository;
    public DeleteRestoreController() { ... }
    public DeleteRestoreController(IRepository Repository) { ... }

    public virtual Action DeleteConfirmed(int id)
    {
        Supplier s = db.Suppliers.Find(id);
        s.Deleted = true;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
}

如果您需要与 ProductsController 中的该行为不同,您可以简单地覆盖该方法。

public class ProductsController : DeleteRestoreController
{
    public override void DeleteConfirmed()
    {
        //override the logic
    }
}

您总是可以更进一步并实现一个通用存储库,但我的应用程序中从未超过 6-8 个控制器,也没有创建过一次。

编辑我刚刚在 cmets 中读到,实体会从控制器中的 Suppliers 更改,因此如果您不实现,实现基本控制器将没有多大意义一个通用接口也是如此。罗伯特·哈维(Robert Harvey)提出了一个很好的观点,他指出复杂性必须在某个地方

【讨论】:

  • 我认为 Robert Harvey 是对的,就我而言,通用存储库可能会拯救我。现在我有 10 个控制器,我预计至少还有 10 个。我有这么多,因为我几乎独立管理每个实体,在这种情况下,我将它们关联起来。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-03
  • 2015-03-20
相关资源
最近更新 更多