MVC 3 - 这将如何工作?

发布于 2024-11-04 04:01:42 字数 2622 浏览 1 评论 0原文

我一年多前就发表了这篇文章,我认为更新它是有意义的,因为它已经获得了相当多的浏览量。

我要么错过了一些东西,要么微软真的把 MVC 搞砸了。我从事 Java MVC 项目,它们干净、简单。然而,在我看来,这完全是一团糟。 NerdDinner 等在线示例和 ASP.Net 上讨论的项目都太基础了,因此它们“简单”工作。如果这听起来很消极,请原谅,但这是我迄今为止的经验。

我有一个存储库和一个与存储库通信的服务。控制器呼叫服务人员。

我的数据层不是独立于持久性的,因为这些类是由 SQL Metal 生成的。因此我有很多不必要的功能。理想情况下我想要 POCO,但我还没有找到实现这一目标的好方法。

*更新:当然,微软并没有搞砸任何事情——我搞砸了。我并不完全理解我可以使用的工具。我所做的主要缺陷是我选择了错误的技术来持久化我的实体。 LINQ to SQL 在有状态应用程序中运行良好,因为可以轻松跟踪数据上下文。然而,在无状态上下文中情况并非如此。什么才是正确的选择?实体框架代码优先或仅代码工作得很好,但更重要的是,这并不重要。 MVC 或前端应用程序一定不应该知道数据是如何持久化的。 *

创建实体时,我可以使用对象绑定:

[HttpPost]
public ActionResult Create(Customer c)
{
    // Persistance logic and return view
}    

这效果很好,MVC 在幕后进行一些绑定,一切都“非常好”。

这不是“Jolly Good”。客户是一个领域模型,更糟糕的是,它依赖于持久介质,因为它是由 SQL Metal 生成的。我现在要做的是设计我的领域模型,该模型独立于数据存储或表示层。然后,我会从我的域模型创建视图模型并使用它。

一旦我想做一些更复杂的事情,例如 - 保存链接到客户的订单,一切似乎都会中断

    [HttpPost]
    public ActionResult Create(Order o)
    {
        // Persistance logic and return view
    }

:订单我需要客户或至少客户 ID。 CustomerId 存在于视图中,但当它到达 Create 方法时,它已经丢失了 CustomerId。我不喜欢坐下来调试 MVC 代码,因为无论哪种方式我都无法在托管环境中更改它。

好吧,抱歉,这里有点抱怨。我现在要做的是创建一个名为 NewOrder、SaveOrder 或 EditOrder 的视图模型,具体取决于我想要实现的目标。该视图模型将包含我感兴趣的所有属性。顾名思义,开箱即用的自动绑定将绑定提交的值,并且不会丢失任何内容。如果我想要自定义行为,那么我可以实现自己的“绑定”,它将完成这项工作。

替代方法是使用 FormCollection:

[HttpPost]
public ActionResult Create(FormCollection collection)
{
   // Here I use the "magic" UpdateModel method which sometimes works and sometimes doesn't, at least for LINQ Entities.               
}

这在书籍和教程中使用,但我没有看到任何意义。方法有一个替代方案:TryUpdateModel - 如果此崩溃或模型无效,它会尝试以任何一种方式更新它。您如何确定这会起作用?

与视图模型的自动绑定在大多数情况下都有效。如果没有,那么您可以覆盖它。你怎么知道它永远有效?你对它进行单元测试,你就睡得很好。

我尝试过的另一种方法是使用 ViewModel - 带有验证规则的包装对象。这听起来是个好主意,只是我不想向实体类添加注释。这种方法非常适合显示数据,但是在写入数据时该怎么办呢?

[HttpPost]
public ActionResult Create(CustomViewWrapper submittedObject)
{
    // Here I'd have to manually iterate through fields in submittedObject, map it to my Entities, and then, eventually, submit it to the service/repository.
}    

** 视图模型是一个很好的前进方向。必须有一些从视图模型到域模型的映射代码,然后可以将其传递给相关服务。这不是正确的方法,但它是这样做的一种方法。自动映射工具是您最好的朋友,您应该找到适合您要求的工具,否则您将编写大量样板代码。**

我是否遗漏了某些内容,或者这就是 Microsoft MVC3 应该工作的方式吗?我不明白这如何简化事情,特别是与 Java MVC 相比。

如果这听起来很负面,我很抱歉,但这是我迄今为止的经历。我很欣赏这个框架正在不断改进,引入了像 UpdateModel 这样的方法,但是文档在哪里?也许是时候停下来思考一下?我希望我的代码始终保持一致,但根据我迄今为止所看到的情况,我不相信这是正确的前进方向。

我喜欢这个框架。有太多东西需要学习,而且没有比以往任何时候都更令人兴奋的了。也许应该再发表一篇关于网络表单的文章。我希望这对您有所帮助。

I have made this post over a year ago, and I think it makes sense to update it as it's getting quite a few views.

I'm either missing something out or Microsoft has really messed up MVC. I worked on Java MVC projects and they were clean and simple. This is however a complete mess IMO. Examples online such as NerdDinner and projects discussed on ASP.Net are too basic, hence why they "simply" work. Excuse if this sounds negative, but this is my experience so far.

I have a repository and a service that speaks to the repository. Controllers call service.

My data layer is NOT persistence independent, as the classes were generated by SQL metal. Because of this I have a lot of unnecessary functionality. Ideally I'd like to have POCO, but I didn't find a good way to achieve this yet.

*Update: Of course Microsoft hasn't messed anything up - I did. I didn't fully understand the tools that were at my disposal. The major flaw in what I have done, was that I have chosen a wrong technology for persisting my entities. LINQ to SQL works well in stateful applications as the data context can be easily tracked. However, this is not a case in stateless context. What would be the right choice? Entity Framework code first or code only work pretty well, but what's more importantly, is that it shouldn't matter. MVC, or front end applications must should not aware of how data is persisted. *

When creating entites I can use object binding:

[HttpPost]
public ActionResult Create(Customer c)
{
    // Persistance logic and return view
}    

This works great, MVC does some binding behind the scene and everything is "jolly good".

It wasn't "Jolly Good". Customer was a domain model, and what was worse, it was dependent on persistence medium, because it was generated by SQL metal. What I would do now, is design my domain model, which would be independent of data storage or presentation layers. I would then create view model from my domain model and use that instead.

As soon as I'd like to do some more complex, e.g. - save Order which is linked to the customer everything seems to break:

    [HttpPost]
    public ActionResult Create(Order o)
    {
        // Persistance logic and return view
    }

To persist an order I need Customer or at least CustomerId. CustomerId was present in the view, but by the time it has got to Create method, it has lost CustomerId. I don't fancy sitting around debugging MVC code as I won't be able to change it in a hosting envrionment either way.

Ok, a bit of moaning here, sorry. What I would do now, is create a view model called NewOrder, or SaveOrder, or EditOrder depending on what I'm trying to achieve. This view model would contain all the properties that I'm interested in. Out-of-the-box auto binding, as the name implies, will bind submitted values and nothing will be lost. If I want custom behaviour, then I can implement my own "binding" and it will do the job.

Alternative is to use FormCollection:

[HttpPost]
public ActionResult Create(FormCollection collection)
{
   // Here I use the "magic" UpdateModel method which sometimes works and sometimes doesn't, at least for LINQ Entities.               
}

This is used in books and tutorials, but I don't see a point in a method which has an alternative: TryUpdateModel - if this crashes or model is invalid, it attempts to update it either way. How can you be certain that this is going to work?

Autobinding with view models will work the most of the time. If it doesn't, then you can override it. How do you know it will always work? You unit test it and you sleep well.

Another approach that I have tried is using ViewModel - wrapper objects with validation rules. This sounds like a good idea, except that I don't want to add annotations to Entity classes. This approach is great for displaying the data, but what do you do when it comes to writing data?

[HttpPost]
public ActionResult Create(CustomViewWrapper submittedObject)
{
    // Here I'd have to manually iterate through fields in submittedObject, map it to my Entities, and then, eventually, submit it to the service/repository.
}    

** View model is a good way forward. There would have to be some mapping code from view model to the domain model, which can then be passed to the relevant service. This is not a correct way, but it's one way of doing it. Auto mapping tools are you best friends and you should find the one that suits your requirements, otherwise you'll be writing tons of boilerplate code.**

Am I missing something out or is this the way Microsoft MVC3 should work? I don't see how this is simplifying things, especiialy in comparisson to Java MVC.

I'm sorry if this sounds negative, but this has been my experience so far. I appreciate the fact that the framework is constantly being improved, methods like UpdateModel get introduced, but where is the documentation? Maybe it's time to stop and think for a little bit? I prefer my code to be consistent throughout, but with what I have seen so far, I have no confidence whatsoever that this is a right way forward.

I love the framework. There is so much to learn and it's not a lot more exciting then it has ever been. Should probably make another post regarding web forms. I hope this is helpful.

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

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

发布评论

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

评论(7

水水月牙 2024-11-11 04:01:42

1) 对于保存订单且没有CustomerId的情况。如果 Order 上有一个 CustomerId 属性,并且您有一个强类型视图,那么您可以通过添加将其保留回您的控制器操作

@Html.HiddenFor(model => model.CustomerId)

。这样做将使默认模型绑定器为您填充内容。

2)关于使用视图模型,我推荐这种方法。如果您使用 AutoMapper 之类的东西,您可以减轻冗余映射场景的一些痛苦。如果您使用类似 Fluent Validation 的东西,那么您可以很好地分离验证问题。

这里有一个很好的链接通用 ASP.NET MVC 实现方法。

1) For the case of saving an order, and not having CustomerId present. If Order has a CustomerId property on it, and you have a stongly typed view, then you can persist this back to your controller action by adding

@Html.HiddenFor(model => model.CustomerId)

Doing this will have the default model binder populate things for you.

2) With respect to using a view model, I would recommend that approach. If you utilize something like AutoMapper you can take some of the pain out of redundant mapping scenarios. If you use something like Fluent Validation then you can separate validation concerns nicely.

Here's a good link on a general ASP.NET MVC implementation approach.

黑白记忆 2024-11-11 04:01:42

我认为您的问题不在于 asp.net MVC,而在于您选择一起使用的所有部分。

你想要原始而简单的吗?

到处使用 POCO,并在需要的地方实现存储库。

我没有使用过 Java MVC,但如果您在其中包含如何解决特定问题,那么整个问题看起来就不那么像咆哮了。

让我们澄清一些误解或可能的误解:

  • 您可以通过帖子将复杂的对象传递到视图。但您只想在有意义的情况下才这样做,请参阅下一个项目符号
  • 您在那里选择的示例会引起一些警报。接受订单的客户数据或客户 ID 而不检查授权可能是一个很大的安全漏洞。对于订单也可以这样说,具体取决于您接受/允许的内容。这是使用 ViewModel 的一个巨大案例,无论 POCO、LINQ、Asp.net MVC 还是 Java MVC。
  • 您可以将未通过帖子显示的简单值传递到视图。它是通过隐藏字段(asp.net MVC 支持非常简单地使用模型值)完成的,并且在某些情况下它会为您生成隐藏字段。
  • 您绝不会被迫将 linq2sql 与 Asp.net MVC 一起使用。如果您发现它不符合您想要的使用方式,请远离它。请注意,我喜欢 linq2sql,但它如何与您对使用 asp.net mvc 可以做什么的看法联系在一起很奇怪。
  • “我从事 Java MVC 项目,它们干净简单”。从事项目与自己设计项目不同。设计技能确实会影响你从任何事物中得到什么。并不是说你的情况,只是想指出这一点,因为缺乏 Java MVC 中缺少的细节。
  • “我的数据层不是持久性独立的,因为类是由 SQL Metal 生成的。因此,我有很多不必要的功能。理想情况下,我想要 POCO,但我没有找到实现此目的的好方法然而”。您选择了错误的技术,linq2sql 并不适合该要求。在我使用它的项目中这并不是一个问题,但一切的设计方式都不像你看起来那样与具体细节相关。也就是说,转移到其他事情上吧。顺便说一句,您应该分享您在 Java MVC 中使用的内容。
  • “CustomerId 存在于视图中,但当它到达 Create 方法时,它已经丢失了 CustomerId。”如果属性是有序的,那么您可以打赌您的代码存在错误。现在,这将是一个完全不同的真正问题,为什么它不使用 CustomerId / 这样的问题会随之而来:您的 Customer 类、视图、您传递给视图的内容...答案将包括,但是不限于:检查浏览器中的 HTML 源代码以查看您真正在源代码中发布的值(或者使用 fiddler 查看相同的值),确保 CustomerId 在将其传递给视图时确实具有该值。
  • 您说:““神奇的”UpdateModel 方法有时有效,有时无效”。这不是魔法,您可以看到它的作用,并且当然可以找到有关它的信息。您发布的信息中存在某些问题,我的赌注是非可选字段或解析的信息的错误值......视图支持为此添加验证。如果没有验证,这可能会缺乏。
  • 您在评论中说道:“调用 UpdateModel 后,我无法显式设置 CustomerId,我必须检索客户对象,然后将其分配给订单,这似乎是一种开销,因为我需要的只是 CustomerId “...您正在接受作为用户输入的 CustomerId(即使它是隐藏字段),您确实想要验证该输入。另外,您自相矛盾,您声称只需要 CustomerId,但随后又说您需要与订单绑定相关的完整客户对象。就是这样,如果您只绑定 CustomerId,您仍然需要获取该 Customer 并将其分配给该属性。除了场景之外没有什么魔力...
  • 另外在评论中:“更新模型是我现在完全避免的事情,因为我不知道它将如何与 LINQ 实体一起运行。在视图模型类中,我创建了构造函数将 LINQ 实体转换为我的视图模型。这减少了控制器中的代码量,但仍然感觉不对”。使用 ViewModel(或 EditModel)的原因并不是因为它是 linq2sql ...而是因为,除了许多其他原因之外,您正在公开一个模型,该模型允许进行超出您实际希望允许用户修改的操作。暴露原始模型(如果它具有不允许用户修改的字段)才是真正的问题。

I don't think your issue is with asp.net MVC but with all the pieces You Choose to use together.

You want it raw and simple?

Use POCOs all around, and implement the repository where you need it.

I haven't used Java MVC, but it'd make the whole question look less like a rant if you include how you solved the particular problem in there.

Let's clear some misconceptions or maybe miscommunication:

  • You can pass complex objects through a post to the view. But you only want to do so if it makes sense, see next bullet
  • The sample you picked there rings some alarms. Accepting Customer data or CustomerID for an order and not checking authorization can be a Big security hole. The same could be said for an Order depending on what you are accepting/allowing. This is a Huge case for the use of ViewModels, regardless of POCOs, LINQ, Asp.net MVC or Java MVC.
  • You can pass simple values not being showed through a post to the view. It's done with hidden fields (which asp.net MVC supports very simply to use the model value), and in some scenarios it generates the hidden fields for you.
  • You are in no way forced to use linq2sql with Asp.net MVC. If you find it lacking for how you intend to use it, move away from it. Note I love linq2sql, but how it is tied to your view of what you can do with asp.net mvc is weird.
  • " I worked on Java MVC projects and they were clean and simple". Working on a project is not the same as designing the project yourself. Design skills does affect what you get out of anything. Not saying is your case, but just wanted to point that out given the lack of specifics on what you're missing from Java MVC.
  • "My data layer is NOT persistence independent, as the classes were generated by SQL metal. Because of this I have a lot of unnecessary functionality. Ideally I'd like to have POCO, but I didn't find a good way to achieve this yet". You picked the wrong technology, linq2sql is Not meant to fit that requirement. It haven't been a problem in the projects I've used it, but everything is designed in such a way that way less tied to its specifics than you seem to be. That said, just move to something else. btw, You should have shared what you used with Java MVC.
  • "CustomerId was present in the view, but by the time it has got to Create method, it has lost CustomerId." If the property is in Order, You can bet your code has the bug. Now, that'd have been a totally different Real question, why it isn't using the CustomerId / such question would come with: your Customer class, the View, what you are passing to the View ... answers would include, but not be limited to: inspect the HTML source in the browser to see what value you are really posting with the source (alternatively use fiddler to see the same), make sure that CustomerId really has the value when you pass it to the View.
  • You said: ""magic" UpdateModel method which sometimes works and sometimes doesn't". It's not magic, you can see what it does and certainly find information on it. Something is off in the information you are posting, my bet is non optional fields or wrong values for information that's parsed ... views support adding validations for that. Without the validations, this can be lacking.
  • You said in a comment: "After UpdateModel is called, i can't explicitly set the CustomerId, I'll have to retrieve a customer object and then assign it to the order, which seems like an overhead as all that I need is CustomerId" ... you are accepting a CustomerId that is user input (even if it is a hidden field), you really want to Validate that input. Additionally you are contradicting yourself, you claim to just need CustomerId, but then you say you need the full Customer Object related to the order bound. Which is it, if you are only binding the CustomerId, you still need to go get that Customer and assign it to the property. There is no magic besides the scenes ...
  • Also in a comment: "Update model is something I'm avoiding completely now as I don't know how it will behave with LINQ entities. In the view model class I have created constructor that converts LINQ entity to my view model. This decreased amount of code in controller, but still doesn't feel right". Reason to use ViewModel (or EditModel) is not because it is linq2sql ... it is because, among many other reasons, you are exposing a model that allows to manipulate way beyond what you actually want to allow the user to modify. Exposing the raw model, if it has fields the user shouldn't be allowed to modify, is the real issue.
醉南桥 2024-11-11 04:01:42

如果您的视图定义正确,那么您可以轻松执行此操作>

    [HttpPost]
    public ActionResult Create(Order o, int CustomerId)
    {
        //you got the id, life back to jolly good (hopefully)
        // Persistance logic and return view
    }

编辑:

正如attadieni提到的,​​通过正确的观点,我的意思是你在表单标签中有类似的东西>

@Html.HiddenFor(model => model.CustomerId)

ASP.NET MVC 会自动绑定到相应的参数。

If your view is correctly defined then you can easily do this >

    [HttpPost]
    public ActionResult Create(Order o, int CustomerId)
    {
        //you got the id, life back to jolly good (hopefully)
        // Persistance logic and return view
    }

EDIT:

as attadieni mentioned, by correct view I meant you have something like this inside the form tag >

@Html.HiddenFor(model => model.CustomerId)

ASP.NET MVC will automatically bind to the respective parameters.

染柒℉ 2024-11-11 04:01:42

我一定是错过了这个问题。

正如您所说,您有一个带有 Create 操作的控制器 Order:

public class OrderController()
{
    [HttpGet]
    public ViewResult Create()
    {
        var vm = new OrderCreateViewModel { 
            Customers = _customersService.All(),
            //An option, not the only solution; for simplicities sake
            CustomerId = *some value which you might already know*; 
            //If you know it set it, if you don't use another scheme.
        }                             
        return View(vm);    
    }

    [HttpPost]
    public ActionResult Create(OrderCreateViewModel model)
    {
        // Persistance logic and return view
    }  
}

Create 操作回发一个 OrderCreateViewModel 类型的视图模型,如下所示。

public class OrderCreateViewModel 
{
    // a whole bunch of order properties....
    public Cart OrderItems { get; set; }
    public int CustomerId { get; set; }

    // Different options
    public List<Customer> Customers { get; set; } // An option
    public string CustomerName { get; set; } // An option to use as a client side search
}

您的视图有一个客户下拉列表,您可以将其作为属性添加到视图模型或文本框中,通过 JQuery 连接到该文本框以在服务器端进行搜索,在其中您可以在匹配时设置 CustomerId 的隐藏字段,但是你决定这样做。如果您已经提前知道 customerId(其他一些帖子似乎暗示了这一点),那么只需将其设置在视图模型中并绕过上述所有内容即可。

您拥有所有订单数据。您已将此订单附加到该客户的客户 ID。你可以走了。

“为了保留订单,我需要 Customer 或至少 CustomerId。CustomerId 存在于视图中,但当它到达 Create 方法时,它已经丢失了 CustomerId。”

什么?为什么?如果 CustomerId 位于视图、设置和回发中,那么它位于 HttpPost Create 方法的模型中,而这正是您需要它的位置。你说它丢失了是什么意思?

ViewModel 被映射到 order 类型的 Model 对象。正如建议的,使用 AutoMapper 很有帮助......

[HttpPost]
public ActionResult Create(OrderCreateViewModel model)
{
    if(!ModelState.IsValid)
    {
      return View(model);
    }   

    // Persistance logic and return view

    var orderToCreate = new Order();

    //Build an AutoMapper map
    Mapper.CreateMap<OrderCreateViewModel, Order>();

    //Map View Model to object(s)
    Mapper.Map(model, orderToCreate);       

    //Other specialized mapping and logic

    _orderService.Create(orderToCreate);

    //Handle outcome. return view, spit out error, etc.
}  

这不是必需的,您可以手动映射它,但它只是让事情变得更容易。

你就准备好了。如果您不想使用数据注释进行验证,那么可以在服务层中进行,使用提到的流畅验证库,无论您选择什么。使用所有数据调用服务层的 Create() 方法后,就可以开始了。
哪里断了?我们缺少什么?

ataddeini的答案是正确的,我只是想展示更多的代码。投票赞成

I must be missing the problem.

You have a controller Order with an Action of Create just like you said:

public class OrderController()
{
    [HttpGet]
    public ViewResult Create()
    {
        var vm = new OrderCreateViewModel { 
            Customers = _customersService.All(),
            //An option, not the only solution; for simplicities sake
            CustomerId = *some value which you might already know*; 
            //If you know it set it, if you don't use another scheme.
        }                             
        return View(vm);    
    }

    [HttpPost]
    public ActionResult Create(OrderCreateViewModel model)
    {
        // Persistance logic and return view
    }  
}

The Create action posts back a view model of type OrderCreateViewModel that looks like such.

public class OrderCreateViewModel 
{
    // a whole bunch of order properties....
    public Cart OrderItems { get; set; }
    public int CustomerId { get; set; }

    // Different options
    public List<Customer> Customers { get; set; } // An option
    public string CustomerName { get; set; } // An option to use as a client side search
}

Your view has a dropdown list of customers which you could add as a property to the viewmodel or a textbox which you wire up to to searching on the server side via JQuery where you could set a hidden field of CustomerId when a match is made, however you decide to do it. And if you already know the customerId ahead of time (which some of the other posts seems to imply) then just set it in the viewmodel and bypass all the above.

You have all of your order data. You have the customer Id of the customer attached to this order. You're good to go.

"To persist an order I need Customer or at least CustomerId. CustomerId was present in the view, but by the time it has got to Create method, it has lost CustomerId."

What? Why? If CustomerId was in the view, set, and posted back, it's in the model for the HttpPost Create method which is exactly where you need it. What do you mean it's being lost?

The ViewModel gets mapped to a Model object of type order. As suggested, using AutoMapper is helpful...

[HttpPost]
public ActionResult Create(OrderCreateViewModel model)
{
    if(!ModelState.IsValid)
    {
      return View(model);
    }   

    // Persistance logic and return view

    var orderToCreate = new Order();

    //Build an AutoMapper map
    Mapper.CreateMap<OrderCreateViewModel, Order>();

    //Map View Model to object(s)
    Mapper.Map(model, orderToCreate);       

    //Other specialized mapping and logic

    _orderService.Create(orderToCreate);

    //Handle outcome. return view, spit out error, etc.
}  

It's not a necessity, you can map it manually, but it just makes things easier.

And you're set. If you don't want to use data annotations for validation, fine, do it in the service layer, use the fluent validation library mentioned, whatever you choose. Once you call the Create() method of your service layer with all the data, you're good to go.
Where's the disconnect? What are we missing?

ataddeini's answer is correct, I'm just trying to show a bit more code. Upvote ataddeini

橘和柠 2024-11-11 04:01:42

如果客户 ID 已存在于订单模型中(在本示例中),则无需扩展方法签名即可使用它。如果您在渲染视图上查看源代码,客户 ID 是否正确地在表单内的隐藏字段中发出?您是否在订单模型类上使用 [Bind] 属性并无意中阻止了客户 ID 的填充?

If the Customer Id is already in the Order model (in this example) it should be available without extending the method signature. If you view the source on the rendered view, is the customer id correctly emitted in a hidden field within the form? Are you using the [Bind] attribute on the Order model class and inadvertently preventing the Customer Id from being populated?

梦醒灬来后我 2024-11-11 04:01:42

我认为 Order 表将包含一个 CustomerID 字段,如果是这样,唯一的问题是您可能没有在视图中包含任何控件来保留该值,然后就会丢失。

尝试遵循这个例子。

1) 发送到视图之前的 GET 操作,假设您此时分配了 CustomerID。

public ActionResult Create()
        {
            var o = new Order();
            o.CustomerID = User.Identity.Name; // or any other wher you store the customerID
            return View(o);
        }

2)视图,如果您不使用任何控件来控制CustomerID,如文本框、组合框等,则必须使用隐藏字段来保留值。

@using (Html.BeginForm())
    {
        @Html.HiddenFor(m => m.CustomerID)

        <label>Requested Date:</label>
        @Html.TextBoxFor(m => m.DateRequested)

        ...
    }

3) 最后,POST 操作获取并保存订单。在这里,由于CustomerID被保留在隐藏值中,Model Binder会自动将所有Form值放入Order对象o中,然后您只需使用CRUD方法并将其持久化即可。

[HttpPost]
public ActionResult Create(Order o)
        {
            return View();
        }

可以采用两种方法来实现此目的,一种是隐式保存所有模型值,即使未在视图中使用,另一种是仅保留那些使用的值。我认为 MVC 正在做正确的事情来遵循后来的做法,避免不必要地为更大的模型保留大量垃圾,而唯一的想法是,举个例子,一个 CustomerName,不知怎的,它可以让你控制在整个过程中保留哪些数据。整个循环动作-视图-动作并节省内存。

对于更复杂的场景,并非所有字段都在同一模型中,您需要使用 ViewModel。例如,对于细节场景,您将创建一个具有两个属性的 OrderViewModel:Order o 和 IEnumerable<<。订单详情>> od,但同样,您需要显式使用视图中的值,或使用隐藏字段。

在最近的版本中,您现在可以使用 POCO 类和 Code-First,这使得一切变得更干净、更容易,您可能想尝试 EF4 + CTP5。

I would think the Order table would include a CustomerID field, if so, the only problem is maybe you are not including any control in the view to keep that value, then is lost.

Try to follow this example.

1) GET action before sending to the View, let's say you assign the CustomerID at this point.

public ActionResult Create()
        {
            var o = new Order();
            o.CustomerID = User.Identity.Name; // or any other wher you store the customerID
            return View(o);
        }

2) The View, if you don't use any control for the CustomerID, like textbox, combobox, etc, you must use a hidden field to keep the value.

@using (Html.BeginForm())
    {
        @Html.HiddenFor(m => m.CustomerID)

        <label>Requested Date:</label>
        @Html.TextBoxFor(m => m.DateRequested)

        ...
    }

3) Finally, the POST action to get and persist the order. In here, as CustomerID was kept in the hidden value, the Model Binder will automatically put all the Form values into the Order object o, then you just need to use CRUD methods and persist it.

[HttpPost]
public ActionResult Create(Order o)
        {
            return View();
        }

Can be two approaches for this, one to implicit save all Model values even if not used in the View, and the other is to keep only those values used. I think MVC is doing the right thing to follow the later, avoid unnecessary keep a lot of junk for bigger models, when the only think is, to name one, a CustomerName, somehow it can give you control on what data to keep through the whole cycle action-view-action and save memory.

For more complex scenarios, where not all fields are in the same model, you need to use ViewModels. For example for mater-detail scenarios you would create a OrderViewModel that has two properties: Order o, and IEnumerable< OrderDetail > od, but again, you will need explicit use the values in the View, or use hidden fields.

In recent releases now you can use POCO classes and Code-First that makes all cleaner and easier, You may want to try EF4 + CTP5.

迟到的我 2024-11-11 04:01:42

如果您正在使用服务(又名:服务层、业务门面)来处理 OrderModel,您可以提取一个接口,并让您的 ViewModel/DTO 来实现它,以便您可以将 ViewModel/DTO 传回给服务。

如果您使用存储库直接管理控制器中的数据(没有服务层),那么您可以使用从存储库加载对象然后对其执行 UpdateModel 的好旧方法来实现。

[HttpPost]
public ActionResult Create(string customerCode, int customerId, Order order)
{
    var cust = _customerRepository.Get(customerId);
    cust.AddOrder(order);//this should carry the customerId to the order.CustomerId
}

另外,URL 可能会在有意义的地方有所帮助,我的意思是您可以在 url 中添加客户标识符来创建订单。

UpdateModel 应该可以工作,如果您的 FormCollection 具有不可为 null 的属性值,并且它们在 FormCollection 中为空/null,则 UpdateModel 应该失败。

if you are using services (aka; service layer, business facade), to process lets say the OrderModel, you can extract an Interface, and get your ViewModel/DTO to implement it, so that you can pass back the ViewModel/DTO to the service.

If you are using Repositories to directly manage the data (without a servie layer) in the controller, then you can do it the good old way of Loading the object from a repository and then doing an UpdateModel on it.

[HttpPost]
public ActionResult Create(string customerCode, int customerId, Order order)
{
    var cust = _customerRepository.Get(customerId);
    cust.AddOrder(order);//this should carry the customerId to the order.CustomerId
}

Also, URLs might help a bit where it makes sense, I mean you can add the customer identifier in the url to create the order for.

UpdateModel should work, if your FormCollection has values for non-nullable properties and they are empty/null in the FormCollection, then UpdateModel should fail.

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