Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using DeepUpdateTests.Models;
using Microsoft.AspNet.OData;
using Microsoft.AspNet.OData.Routing;
using Microsoft.AspNetCore.Mvc;
using Microsoft.OData.Edm;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;

namespace DeepUpdateTests.Controllers
{
public class HistoryController : ODataController
{
// In-memory static list for demonstration. Replace with persistent storage as needed.
private static readonly IList<History> _history;
private static readonly IEdmModel _edmModel = EdmModelBuilder.GetEdmModel();
private static readonly IEdmEntityType _customerEdmType = _edmModel.SchemaElements
.OfType<IEdmEntityType>()
.First(e => e.Name == nameof(Customer));

static HistoryController()
{
var delta = GetDeltaObject();

_history = new List<History>
{
new History
{
Id = 1,
CustomerDelta = DeltaObjectSerializer.AsSerializedDeltaObject(delta)
}
};
}

[EnableQuery]
public IActionResult Get()
{
return Ok(_history);
}

private static EdmDeltaEntityObject GetDeltaObject()
{
IEdmModel model = EdmModelBuilder.GetEdmModel();
var customerType = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Customer");

var changedCustomerObject = new EdmDeltaEntityObject(customerType);
changedCustomerObject.TrySetPropertyValue("Id", 1);
changedCustomerObject.TrySetPropertyValue("Name", "customer old name");

var orderType = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Order");

var changedOrders = new EdmChangedObjectCollection(orderType);

var changeOrder1Object = new EdmDeltaEntityObject(orderType);
changeOrder1Object.TrySetPropertyValue("Id", 1);
changedOrders.Add(changeOrder1Object);

var changedOrder2Object = new EdmDeltaDeletedEntityObject(orderType);
changedOrder2Object.Id = "http://tempuri.org/Orders(2)";
changedOrder2Object.TrySetPropertyValue("Id", 2);
changedOrders.Add(changedOrder2Object);

var changedOrderObject = new EdmDeltaEntityObject(orderType);
changedOrderObject.TrySetPropertyValue("Id", 1);
changedOrderObject.TrySetPropertyValue("Amount", 8);

// Have nested
var listItemType = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "ListItem");
var changedLists = new EdmChangedObjectCollection(listItemType);
var changeList1Object = new EdmDeltaEntityObject(listItemType);
changeList1Object.TrySetPropertyValue("Id", 1);
changedLists.Add(changeList1Object);

changedOrderObject.TrySetPropertyValue("Items", changedLists);

changedOrders.Add(changedOrderObject);
changedCustomerObject.TrySetPropertyValue("Orders", changedOrders);
return changedCustomerObject;
}
}
}
6 changes: 6 additions & 0 deletions v7.x/DeepUpdateTests/DeepUpdateTests/DeepUpdateTests.http
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ GET {{DeepUpdateTests_HostAddress}}/weatherforecast
###
GET {{DeepUpdateTests_HostAddress}}/odata/Customers

###
GET {{DeepUpdateTests_HostAddress}}/odata/History
OData-Version: 4.01
Accept: application/json


###
GET {{DeepUpdateTests_HostAddress}}/odata/Customers(1)/orders?$expand=list&$deltaToken=abcd
OData-Version: 4.01
Expand Down
116 changes: 116 additions & 0 deletions v7.x/DeepUpdateTests/DeepUpdateTests/Models/DeltaObjectSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//-------------------------------------------------------------------------------------------------
// <copyright file="DeltaObjectSerializer.cs" company="Microsoft">
// Copyright (c) Microsoft. All rights reserved.
// </copyright>
//-------------------------------------------------------------------------------------------------

using Microsoft.AspNet.OData;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Reflection;
namespace DeepUpdateTests.Models
{

/// <summary>
/// Provides serialization capabilities for EdmDelta objects
/// </summary>
public static class DeltaObjectSerializer
{
/// <summary>
/// Serializes an EdmDeltaEntityObject to a JSON string
/// </summary>
/// <param name="deltaObject">The delta object to serialize</param>
/// <returns>A JSON string representation of the delta object</returns>
public static string AsSerializedDeltaObject(EdmDeltaEntityObject deltaObject)
{
if (deltaObject == null)
{
throw new ArgumentNullException(nameof(deltaObject));
}

var jsonObject = new JObject();
SerializeDeltaObject(deltaObject, jsonObject);
return jsonObject.ToString(Formatting.None);
}

/// <summary>
/// Serializes an EdmDeltaComplexObject to a JSON string
/// </summary>
/// <param name="deltaObject">The delta complex object to serialize</param>
/// <returns>A JSON string representation of the complex object</returns>
public static string AsSerializedDeltaObject(EdmDeltaComplexObject deltaObject)
{
if (deltaObject == null)
{
throw new ArgumentNullException(nameof(deltaObject));
}

var jsonObject = new JObject();
SerializeDeltaObject(deltaObject, jsonObject);
return jsonObject.ToString(Formatting.None);
}

private static void SerializeDeltaObject(IDelta deltaObject, JObject jsonObject)
{
// Serialize properties
foreach (var propertyName in deltaObject.GetChangedPropertyNames())
{
object propertyValue;
if (deltaObject.TryGetPropertyValue(propertyName, out propertyValue))
{
JToken valueToken = SerializePropertyValue(propertyValue);
jsonObject.Add(propertyName, valueToken);
}
}
}

private static JToken SerializePropertyValue(object value)
{
if (value == null)
{
return JValue.CreateNull();
}

// Handle any IDelta (both EdmDeltaEntityObject and EdmDeltaComplexObject) recursively
if (value is IDelta delta)
{
var deltaJson = new JObject();
SerializeDeltaObject(delta, deltaJson);
return deltaJson;
}

// Handle collections
if (value is IEnumerable enumerable && !(value is string))
{
var arrayJson = new JArray();
foreach (var item in enumerable)
{
arrayJson.Add(SerializePropertyValue(item));
}

return arrayJson;
}

// Handle primitive types with fallback
return ConvertPrimitiveWithFallback(value);
}

private static JToken ConvertPrimitiveWithFallback(object value)
{
if (value == null)
{
return JValue.CreateNull();
}

switch (value)
{
case Guid g:
return new JValue(g.ToString());
default:
return JToken.FromObject(value);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public static IEdmModel GetEdmModel()
{
var builder = new ODataConventionModelBuilder();
builder.EntitySet<Customer>("Customers");
builder.EntitySet<History>("History");
builder.EntitySet<Order>("Orders");
builder.EntityType<ListItem>();

Expand All @@ -32,6 +33,13 @@ public class Customer
public virtual Order[] Orders { get; set; }
}

public class History
{
public int Id { get; set; }

public string CustomerDelta { get; set; }
}

public class Order
{
public int Id { get; set; }
Expand Down