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

发布于 2024-08-05 09:55:24 字数 1658 浏览 2 评论 0原文

我已经阅读了教程(特别是使用 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 to 支持初始值设定项 实体。

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

I've been going through the tutorials (specifically ones using Linq-To-Entities) and I understand the basic concepts, however some things are giving me issues.

The tutorials usually involve only simple models and forms that only utilize basic create, update and delete statements. Mine are a little more complicated, and I'm not sure I'm going about this the right way because when it comes time to handle the relationships of a half dozen database objects, the tutorials stop helping.

For the post method, the usual way of performing CRUD operations

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

Won't do what I want, because a fully implemented class isn't getting posted to the controller method. I may post individual fields, form collections, or multiple DTO objects and then call a method on a service or repository to take the information I receive from a form post, along with information that it needs to query for or create itself, and then from all of those things, create my database object that I can save.

[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();
}

Am I handling this correctly or am I bastardizing the framework? I never actually use an entity object directly, whenever I query for one I put the information I need in a DTO and base my Views off of that. Same goes with the creation. Is this allowed, or is my avoidance of using entities directly going against the purpose of using the framework?

Edit: I'm also worried about this approach because it requires empty constructors to properly do the LINQ queries because of this error message:

Only parameterless constructors and
initializers are supported in LINQ to
Entities.

This isn't a big deal since I rarely need logic int the constructors, but is this an issue to have no constructors and only public properties?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我不在是我 2024-08-12 09:55:24

_someRepositoryOrService.Add(id, classA, classB);

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

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

如何破坏关注点分离 (SoC)。它执行两个任务:

  1. 将视图数据映射到
  2. 保存到存储库的

实体中显然第一步应该在表示层中完成。为此考虑使用模型绑定器。它还可以帮助您解决构造函数问题,因为您的模型绑定器可以了解构造要求。

另请检查这个优秀的 Jimmy Bogard(《ASP.NET MVC In Action》的合著者)关于 ViewModel 的帖子。这可能会帮助您自动映射。它还提出了一种相反的技术 - 让您的控制器与实体一起工作,而不是 ViewModel!自定义操作过滤器和模型绑定器实际上是消除不属于控制器而是视图和控制器之间的基础结构细节的例程的关键。例如,此处我如何自动化实体检索。 这里是我如何看待控制器应该做什么。

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

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

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

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

_someRepositoryOrService.Add(id, classA, classB);

I would say you couple your repositories with presentation layer. This shouldn't be. Your repositories should only work with entities. Next, notice how your Add method

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

breaks Separation of Concerns (SoC). It performs two tasks:

  1. map view data into entities
  2. save to repository

Obviously the first step should be done in presentation layer. Consider using model binders for this. It can also help you to solve the constructors problem, since your model binders can be made aware of the construction requirements.

Check also this excellent post by Jimmy Bogard (co-author of ASP.NET MVC In Action) about ViewModels. This might help you to automate mapping. It also suggest a reversed technique - make your controllers work with entities, not ViewModels! Custom action filters and model binders are really the key to eliminate routine that that don't really belong to controllers but rather an infrastructure detail between view and controller. For example, here's how I automate entities retrival. Here's how I see what controllers should do.

The goal here is to make controllers contentrate on managing business logic, putting aside all the technical details that do not belong to your business. It's techical constraints that you talk about in this question, and you let them leak into your code. But you can use MVC tools to move the to them infrastructure level.

UPDATE: No, repositories shouldn't handle form data, that's what I mean by "coupling with presentation". Yes, repositories are in the controller, but they don't work with form data. You can (not that you should) make form work with "repositories data" - i.e. entities - and that's what most examples do, e.g. NerdDinner - but not the other way. This is because of the general rule of thumb - higher layers can be coupled with lower ones (presentation coupled with repositories and entities), but never low level should be coupled to higher ones (entities depend on repositories, repositories depend on form model, etc).

The first step should be done in the repository, that's right - except that mapping from ClassX to EntityX does not belong to that step. It's mapping concern - an infrastructure. See for example this question about mapping, but generally if you have two layers (UI and repositories) they shouldn't care about mapping - a mapper service/helper should. Beside Jimmy's blog, you can also read ASP.NET MVC In Action or simply look at their CodeCampServer for how they do mapping with IEntityMapper interfaces passed to controller constructors (note that this is more manual and less-work approach that Jimmy Bogard's AutoMapper).

One more thing. Read about Domain Driven Design, look for articles, learn from them, but you don't have to follow everything. These are guidelines, not strict solutions. See if your project can handle that, see if you can handle that, and so on. Try to apply this techniques since they're generally the excellent and approved ways of doing development, but don't take them blindly - it's better to learn along the way than to apply something you don't understand.

何以笙箫默 2024-08-12 09:55:24

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

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

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

最后,您主要将实体框架用作代码生成器,它不会生成非常有用的代码,因此您可能需要研究更符合您的需求的其他代码生成器或工具或框架。

I would say using DTOs and wrapping the Entity Framework with your own data access methods and business layer is a great way to go. You may end up writing a lot of code, but it's a better architecture than pretending the Entity Framework generated code is your business layer.

These issues aren't really necessarily tied to ASP.NET MVC in any way. ASP.NET MVC gives basically no guidance on how to do your model / data access and most of the samples and tutorials for ASP.NET MVC are not production worthy model implementations, but really just minimal samples.

It seems like you are on the right track, keep going.

In the end, you are using Entity Framework mostly as a code generator that isn't generating very useful code and so you may want to look into other code generators or tools or frameworks that more closely match your requirements.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文