我的ASP.NET MVC应用程序是否正确构建?

时间:2009-09-20 03:18:41

标签: asp.net-mvc entity-framework crud dto

我一直在阅读这些教程(特别是那些使用Linq-To-Entities的教程)并且我理解了基本概念,但是有些东西给了我一些问题。

教程通常只涉及仅使用基本创建,更新和删除语句的简单模型和表单。我有点复杂,我不确定我是否正确地采用这种方式,因为当需要处理六个数据库对象的关系时,教程就会停止帮助。

对于post方法,执行CRUD操作的常用方法

entities.AddToTableSet(myClass);
entities.SaveChanges();

不会做我想要的,因为完全实现的类没有被发布到控制器方法。我可以发布单个字段,表单集合或多个DTO对象,然后调用服务或存储库上的方法来获取从表单发布的信息,以及它需要查询或创建自身的信息,然后从所有这些,创建我可以保存的数据库对象。

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Add(int id, [Bind(Exclude = "Id")] ClassA classA,
                        [Bind(Exclude = "Id")]ClassB classB)
{
   // Validation occurs here

   if(!ModelState.IsValid)
      return View();

   try
   {
      _someRepositoryOrService.Add(id, classA, classB);
      return RedirectToAction("Index", new { id = id });
   }
   catch(Exception ex)
   {
      // Logging and exception handling occurs here
   }
}


public void Add(int id, ClassA classA, ClassB classB)
{
    EntityA eA = new EntityA
    {
        // Set a bunch of properties using the two classes and
        // whatever queries are needed
    };

    EntityB eB = new EntityB
    {
        // Set a bunch of properties using the two classes and
        // whatever queries are needed
    };

    _entity.AddToEntityASet(eA);
    _entity.AddToEntityBSet(eB);
    _entity.SaveChanges();
}

我是正确处理此问题还是我对框架进行了混蛋?我从来没有直接使用实体对象,每当我查询一个实体对象时,我将我需要的信息放在DTO中并将我的视图基于此。创作也是如此。这是允许的,还是我避免使用实体直接违背使用框架的目的?

编辑:我也担心这种方法,因为它需要空的构造函数来正确执行LINQ查询,因为这个错误消息:

  

只有无参数构造函数和   LINQ支持初始化程序   实体。

这不是什么大不了的事,因为我很少需要构造函数中的逻辑,但这是一个没有构造函数和只有公共属性的问题吗?

2 个答案:

答案 0 :(得分:4)

我想说使用DTO并使用您自己的数据访问方法和业务层包装Entity Framework是一个很好的方法。您最终可能会编写大量代码,但它比假装实体框架生成的代码更好的架构是您的业务层。

这些问题并不一定与ASP.NET MVC有任何关系。 ASP.NET MVC基本上没有关于如何进行模型/数据访问的指导,并且ASP.NET MVC的大多数示例和教程都不是生产有价值的模型实现,但实际上只是最小的样本。

看起来你走在正确的轨道上,继续前进。

最后,您主要使用Entity Framework作为代码生成器,它不会生成非常有用的代码,因此您可能希望查看更符合您要求的其他代码生成器或工具或框架。

答案 1 :(得分:4)

_someRepositoryOrService.Add(id,classA,classB);

我想说你将你的存储库与表示层结合起来。这不应该。您的存储库只应与实体一起使用。接下来,注意你的Add方法

public void Add(int id,ClassA classA,ClassB classB)

打破关注点分离(SoC)。它执行两项任务:

  1. 将视图数据映射到实体
  2. 保存到存储库
  3. 显然,第一步应该在表示层完成。考虑使用模型绑定器。它还可以帮助您解决构造函数问题,因为您可以使模型绑定器了解构造要求。

    请查看Jimmy Bogard(ASP.NET MVC In Action的合着者)关于ViewModels的优秀post。这可能有助于您自动化映射。它还建议采用相反的技术 - 使控制器与实体一起工作,而不是ViewModels!自定义操作过滤器和模型绑定器实际上是消除不真正属于控制器的例程的关键,而是视图和控制器之间的基础结构细节。例如,here是我如何自动化实体回溯。 Here我是如何看待控制器应该做的。

    这里的目标是让控制器满足于管理业务逻辑,将所有不属于您业务的技术细节放在一边。你在这个问题中讨论的是技术限制,你让它们泄漏到你的代码中。但您可以使用MVC工具将其移至基础架构级别。

    更新:不,存储库不应该处理表单数据,这就是我所说的“与表示耦合”。是的,存储库位于控制器中,但它们不适用于表单数据。您可以(不应该)使用“存储库数据”(即实体)进行表单工作 - 这就是大多数示例所做的事情,例如: NerdDinner - 但不是另一种方式。这是因为一般的经验法则 - 较高层可以与较低层耦合(表示与存储库和实体相结合),但从不低层应该与较高层耦合(实体依赖于存储库,存储库依赖于表单模型等) )。

    第一步应该在存储库中完成,这是正确的 - 除了从ClassX到EntityX的映射不属于该步骤。这是映射问题 - 基础设施。请参阅示例this关于映射的问题,但通常如果您有两个层(UI和存储库),他们不应该关心映射 - 映射器服务/帮助应该。除了Jimmy的博客,您还可以阅读ASP.NET MVC In Action或者只是看看他们的CodeCampServer他们如何使用传递给控制器​​构造函数的IEntityMapper接口进行映射(请注意,这是Jimmy的更多手动和更少工作的方法)博加德的AutoMapper)。

    还有一件事。阅读有关领域驱动设计,寻找文章,从中学习,但您不必关注所有内容。这些是准则,而不是严格的解决方案查看您的项目是否可以处理它,看看您是否可以处理它,等等。尝试应用这些技术,因为它们通常是优秀且经过批准的开发方式,但不要盲目地对待它们 - 沿途学习比应用你不理解的东西更好。