Как загрузить связанные сущности через MVC4 upshot - PullRequest
1 голос
/ 27 марта 2012

Я получаю простую сущность DTO A, загруженную в мою исходную модель представления, которую можно легко просмотреть с помощью Knockoutjs.

Мой DTO A содержит объекты List.Таким образом, я снова могу рассматривать элементы внутри A.

:

class A
    {
       someprop;
        List<B> childB;
    }
Class B
{
   somepropB;
}

Пока все хорошо.Я могу перебирать данные без проблем.Но если я изменю «someprop» внутри экземпляра A и SaveAll, сервер вообще не будет отвечать.Метод элемента управления updateData даже не вызывается.Если я очищаю childB.Clear () перед передачей его клиенту, все в порядке.

Кажется, что в результате не удастся обновить сущности с коллекциями?

1 Ответ

3 голосов
/ 04 апреля 2012

Есть много работы, если вы хотите, чтобы такой сценарий работал.Апшот только превращает родительские объекты в наблюдаемые предметы.Так что только представление javascript класса A является наблюдаемым нокаутом, представление javascript класса B - нет.Поэтому Upshot не знает о каких-либо изменениях в связанных объектах.

Решение состоит в том, чтобы сопоставить объекты вручную.Чтобы сделать мою жизнь проще, я использовал код из моего примера приложения DeliveryTracker в фрагментах кода ниже.В моей статье в блоге вы можете увидеть пример сопоставления вручную: http://bartjolling.blogspot.com/2012/04/building-single-page-apps-with-aspnet.html, поэтому мои примеры ниже работают с объектами 'delivery' и 'customer'.

Модель домена на стороне сервера

namespace StackOverflow.q9888839.UploadRelatedEntities.Models
{
    public class Customer
    {
        [Key]
        public int CustomerId { get; set; }

        public string Name { get; set; }
        public string Address { get; set; }
        public double Latitude { get; set; }
        public double Longitude { get; set; }

        public virtual ICollection<Delivery> Deliveries { get; set; }
    }

    public class Delivery
    {
        [Key]
        public int DeliveryId { get; set; }
        public string Description { get; set; }
        public bool IsDelivered { get; set; }

        [IgnoreDataMember] //needed to break cyclic reference
        public virtual Customer Customer { get; set; }
        public virtual int CustomerId { get; set; }
    }

    public class AppDbContext : DbContext
    {
        public DbSet<Customer> Customers { get; set; }
        public DbSet<Delivery> Deliveries { get; set; }
    }
}

Контроллер службы данных

Контроллер службы данных предоставляет данные, соответствующие стандартам OData, на "http://localhost:[yourport]/api/dataservice/GetCustomers". Чтобы иметь возможность обновлять как клиентов, так и поставки, вам необходимо определить UpdateCustomer.И функция UpdateDelivery

namespace StackOverflow.q9888839.UploadRelatedEntities.Controllers
{
    public class DataServiceController : DbDataController<AppDbContext>
    {
        //Service interface for Customer
        public IQueryable<Customer> GetCustomers()
        {
            return DbContext.Customers.Include("Deliveries").OrderBy(x => x.CustomerId);
        }
        public void InsertCustomer(Customer customer) { InsertEntity(customer); }
        public void UpdateCustomer(Customer customer) { UpdateEntity(customer); }
        public void DeleteCustomer(Customer customer) { DeleteEntity(customer); }

        //Service interface for Deliveries
        public void InsertDelivery(Delivery delivery) { InsertEntity(delivery); }
        public void UpdateDelivery(Delivery delivery) { UpdateEntity(delivery); }
        public void DeleteDelivery(Delivery delivery) { DeleteEntity(delivery); }
    }
}

Модель домена на стороне клиента

Добавить новый файл javascript, содержащий вашу модель на стороне клиента. Здесь я явно превращаю каждое свойство в наблюдаемую нокаут.для решения вашей проблемы есть строка внутри конструктора объекта Customer, где я отображаю входящие поставки в наблюдаемый массив

/// <reference path="_references.js" />
(function (window, undefined) {

    var deliveryTracker = window["deliveryTracker"] = {}; //clear namespace

    deliveryTracker.DeliveriesViewModel = function () {
        // Private
        var self = this;
        self.dataSource = upshot.dataSources.Customers;
        self.dataSource.refresh();
        self.customers = self.dataSource.getEntities();
    };

    deliveryTracker.Customer = function (data) {
        var self = this;

        self.CustomerId = ko.observable(data.CustomerId);
        self.Name = ko.observable(data.Name);
        self.Address = ko.observable(data.Address);
        self.Latitude = ko.observable(data.Latitude);
        self.Longitude = ko.observable(data.Longitude);

        self.Deliveries = ko.observableArray(ko.utils.arrayMap(data.Deliveries, function (item) {
            return new deliveryTracker.Delivery(item);
        }));

        upshot.addEntityProperties(self, "Customer:#StackOverflow.q9888839.UploadRelatedEntities.Models");
    };

    deliveryTracker.Delivery = function (data) {
        var self = this;

        self.DeliveryId = ko.observable(data.DeliveryId);
        self.CustomerId = ko.observable(data.CustomerId);
        self.Customer = ko.observable(data.Customer ? new deliveryTracker.Customer(data.Customer) : null);
        self.Description = ko.observable(data.Description);
        self.IsDelivered = ko.observable(data.IsDelivered);

        upshot.addEntityProperties(self, "Delivery:#StackOverflow.q9888839.UploadRelatedEntities.Models");
    };

    //Expose deliveryTracker to global
    window["deliveryTracker"] = deliveryTracker;
})(window);

Представление

В index.cshtml, который вы инициализируетеUpshot, укажите пользовательское сопоставление клиента и привяжите viewmodel

@(Html.UpshotContext(bufferChanges: false)
              .DataSource<StackOverflow.q9888839.UploadRelatedEntities.Controllers.DataServiceController>(x => x.GetCustomers())
              .ClientMapping<StackOverflow.q9888839.UploadRelatedEntities.Models.Customer>("deliveryTracker.Customer")
              .ClientMapping<StackOverflow.q9888839.UploadRelatedEntities.Models.Delivery>("deliveryTracker.Delivery")
)
<script type="text/javascript">
    $(function () {
        var model = new deliveryTracker.DeliveriesViewModel();
        ko.applyBindings(model);
    });
</script>

<section>
<h3>Customers</h3>
    <ol data-bind="foreach: customers">
        <input data-bind="value: Name" />

        <ol data-bind="foreach: Deliveries">
            <li>
                <input type="checkbox" data-bind="checked: IsDelivered" >
                    <span data-bind="text: Description" /> 
                </input>
            </li>
        </ol>
    </ol>
</section>

Результаты

При навигацииНа странице индекса список клиентов и связанных с ними поставок будет загружен асинхронно.Все доставки сгруппированы по клиентам и предварительно зафиксированы с помощью флажка, который привязан к свойству поставки IsDelivered.Имя клиента также можно редактировать, поскольку оно связано с элементом INPUT

У меня недостаточно репутации, чтобы опубликовать снимок экрана, поэтому вам придется обойтись без одного

При установке или снятии флажка IsDelivered сейчас Upshot обнаружит изменение и отправит его на контроллер DataService

[{"Id":"0",
    "Operation":2,
    "Entity":{
        "__type":"Delivery:#StackOverflow.q9888839.UploadRelatedEntities.Models",
        "CustomerId":1,
        "DeliveryId":1,
        "Description":"NanoCircuit Analyzer",
        "IsDelivered":true
    },
    "OriginalEntity":{
        "__type":"Delivery:#StackOverflow.q9888839.UploadRelatedEntities.Models",
        "CustomerId":1,
        "DeliveryId":1,
        "Description":"NanoCircuit Analyzer",
        "IsDelivered":false
    }
}]

При изменении имени клиента Upshot отправит изменения, когда поле ввода потеряет фокус

[{
    "Id": "0",
    "Operation": 2,
    "Entity": {
        "__type": "Customer:#StackOverflow.q9888839.UploadRelatedEntities.Models",
        "Address": "Address 2",
        "CustomerId": 2,
        "Latitude": 51.229248,
        "Longitude": 4.404831,
        "Name": "Richie Rich"
    },
    "OriginalEntity": {
         "__type": "Customer:#StackOverflow.q9888839.UploadRelatedEntities.Models",
        "Address": "Address 2",
        "CustomerId": 2,
        "Latitude": 51.229248,
        "Longitude": 4.404831,
        "Name": "Rich Feynmann"
    }
}]

Поэтому, если вы выполните описанную выше процедуру, Upshot обновит для вас родительские и дочерние объекты.

...