Asp.net mvc knockoutjs从/到POCO对象的映射

Asp.net mvc knockoutjs从/到POCO对象的映射,asp.net-mvc,mapping,poco,knockout.js,Asp.net Mvc,Mapping,Poco,Knockout.js,有没有一种方法可以将POCO和knockoutjs映射到可观察的POCO和knockoutjs 我有一门笔记课: public class Note { public int ID { get; set; } public string Date { get; set; } public string Content { get; set; } public string Category { get; set; } public string Backg

有没有一种方法可以将POCO和knockoutjs映射到可观察的POCO和knockoutjs

我有一门笔记课:

public class Note
{
    public int ID { get; set; }
    public string Date { get; set; }
    public string Content { get; set; }
    public string Category { get; set; }
    public string Background { get; set; }
    public string Color { get; set; }
}
这是我的javascript:

$(function () {
    ko.applyBindings(new viewModel());
});

function note(date, content, category, color, background) {
    this.date = date;
    this.content = content;
    this.category = category;
    this.color = color;
    this.background = background;
}

function viewModel () {
    this.notes = ko.observableArray([]);
    this.newNoteContent = ko.observable();

    this.save = function (note) {
        $.ajax({
                url: '@Url.Action("AddNote")',
                data: ko.toJSON({ nota: note }),
                type: "post",
                contentType: "json",
                success: function(result) { }

            });
    }

    var self = this;
    $.ajax({
        url: '@Url.Action("GetNotes")',
        type: "get",
        contentType: "json",
        async: false,
        success: function (data) {
            var mappedNotes = $.map(data, function (item) {
                return new note(item.Date, item.Content, item.Category, item.Color, item.Background);
            });
            self.notes(mappedNotes);
        }
    });
}
忽略未使用save函数的事实(以简化此处的代码)

因此,当我加载页面时,我调用服务器,检索一个Note对象列表,并用javascript映射它。注意ID是如何不映射的,因为我的视图中不需要它

到目前为止还不错,我在屏幕上看到了注释,但是如何将注释保存回服务器呢

我尝试将注释(我只保存新注释而不是整个集合)转换为JSON并将其发送到我的控制器,但我不知道如何访问控制器中的注释。我试过:

    public string AddNote(string date, string content, string category, string background, string color)
    {
        // TODO
    }
但它不起作用。我想要一些像:

public string AddNote(Note note) {}
(顺便问一下,对于只在DB上保存数据的方法,最好的回报是什么?void?)

那么,我是如何做到这一点的?我尝试了knockout.mapping插件,但它非常混乱,我无法让它为我工作


谢谢。ASP.NET MVC的model binder将查找区分大小写的属性。您需要使用与poco对象匹配的属性名称将JSON对象传递回服务器

我通常做两件事中的一件:

  • 使我的javascript对象属性名称大写(这样在JS中,我知道这个对象在某个时候会成为服务器的DTO)

  • 在我的AJAX调用中,我将创建一个匿名对象以传递回服务器(注意,这不需要ko.toJSON):

    (请注意不同的contentType参数)

  • 您需要让ActionMethod接受一个
    (注意)
    ,而不仅仅是参数数组

    另外,因为ModelBinder以两种不同的方式查看发布的值。我很幸运地发布了JSON对象,但没有指定ActionMethod参数名称: 而不是:

        { note: {
            Date: note.date,
            Content: note.content,
            Category: note.category,
            Color: note.color,
            Background: note.background
            }
        }
    
    只要做:

        {
            Date: note.date,
            Content: note.content,
            Category: note.category,
            Color: note.color,
            Background: note.background
        }
    
    (但绑定到集合和复杂类型的数组可能会带来危险……等等)

    至于执行db调用的方法返回的“最佳”签名,我们通常更喜欢使用布尔值,但这也取决于您的需要。显然,如果它是琐碎的数据,void就可以了,但是如果它有点关键,那么您可能希望传递一个布尔值(至少),让您的客户机知道它可能需要重试(特别是在出现并发异常的情况下)

    如果您真的需要让您的客户知道数据库中发生了什么,您可以进入和的世界

    此外,如果您需要根据成功/不成功的数据库提交向用户显示非常具体的信息,那么您可以考虑根据数据库事务中发生的情况创建重定向到特定视图的方法

    最后,关于从服务器获取数据和使用淘汰

  • 同样,如果属性名称大小写相同,或者您创建了一个稍微显式的映射,那么映射插件将起作用
  • 下面是我自己使用JS对象的技巧。initialize函数是我创建的,它应该可以在所有对象中重用,因为它只是说“如果属性名称匹配(小写后),可以通过调用函数(与敲除兼容)来设置它们,或者只指定值:”

    function Note(values){ //values are what just came back from the server
        this.date;
        this.content;
        this.category;
        this.color;
        this.background;
    
        initialize(values); //call the prototyped function at the bottom of the constructor
    };
    
    Note.prototype.initialize = function(values){
        var entity = this; //so we don't get confused
            var prop = '';
            if (values) {
                for (prop in values) {
                    if (values.hasOwnProperty(prop.toLowerCase()) && entity.hasOwnProperty(prop.toLowerCase())) {
                        //the setter should have the same name as the property on the values object
    
                        if (typeof (entity[prop]) === 'function') {
                            entity[prop](values[prop]); // we are assuming that the setter only takes one param like a Knockout observable()
                        } else {// if its not a function, then we will just set the value and overwrite whatever it was previously
                            entity[prop] = values[prop];
                        }
                    }
                }
            }
    };
    

  • 非常棒的史诗般的回答。它非常完美,但是:你能解释我最后一段吗?以及..如何从服务器加载?手动映射,就像我在这里做的那样,或者我必须尝试映射插件?是的,+1是一个很好的回答。这是非常清楚的优秀例子。
        {
            Date: note.date,
            Content: note.content,
            Category: note.category,
            Color: note.color,
            Background: note.background
        }
    
    function Note(values){ //values are what just came back from the server
        this.date;
        this.content;
        this.category;
        this.color;
        this.background;
    
        initialize(values); //call the prototyped function at the bottom of the constructor
    };
    
    Note.prototype.initialize = function(values){
        var entity = this; //so we don't get confused
            var prop = '';
            if (values) {
                for (prop in values) {
                    if (values.hasOwnProperty(prop.toLowerCase()) && entity.hasOwnProperty(prop.toLowerCase())) {
                        //the setter should have the same name as the property on the values object
    
                        if (typeof (entity[prop]) === 'function') {
                            entity[prop](values[prop]); // we are assuming that the setter only takes one param like a Knockout observable()
                        } else {// if its not a function, then we will just set the value and overwrite whatever it was previously
                            entity[prop] = values[prop];
                        }
                    }
                }
            }
    };