Azure移动服务TableController不返回内部对象 [英] Azure Mobile Service TableController not returning inner objects
问题描述
我正在使用表存储创建一个基本的(我的第一个)Azure移动服务,以控制一个简单的事件"应用程序.我的DataObjects包含2种对象类型:Coordinator
和Event
,我希望Coordinators是一个单独的表来存储特定的信息,我不希望它在Events中进行非规范化,但是Events也有一个内部对象Location要存储活动位置的详细信息,但我想存储非规范化的信息,因为我不想与活动分开维护此详细信息.
I am creating a basic (my first) Azure Mobile Service with Table Storage to control a simple Events app. My DataObjects consists of 2 object types: Coordinator
and Event
, I want Coordinators to be a separate table to store specific info that I don't want it denormalized inside the Events, but Events also has a inner object Location to store details for the event's location, but that I want to store denormalized as I don't want to maintain this details separately from the Event.
这里是我到目前为止拥有的对象: 数据对象:
Here the objects I have so far: DataObjests:
public class Coordinator : EntityData {
public string Name { get; set; }
public int Points { get; set; }
public bool IsActive { get; set; }
}
public class Event: EntityData {
public Coordinator Coordinator { get; set; }
public DateTime EventDate { get; set; }
public int Attendees { get; set; }
public Location Location { get; set; }
}
public class Location {
public string Name { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string County { get; set; }
public string PostCode { get; set; }
}
由VS的脚手架生成的作为基本TableController
的控制器,我所做的唯一更改是在事件控制器上公开了MobileServiceContext
,以使Post方法在保存时能够找到现有的协调器,因为客户端仅会发布协调人的ID:
The controllers as basic TableController
generated by VS's scaffolding, the only change I made was to expose the MobileServiceContext
on the Event Controller to enable the Post method to find an existing Coordinator when saving as the client will only post the Coordinator's ID:
public class EventController : TableController<Event> {
private MobileServiceContext context;
protected override void Initialize(HttpControllerContext controllerContext) {
base.Initialize(controllerContext);
context = new MobileServiceContext();
DomainManager = new EntityDomainManager<Event>(context, Request, Services);
}
protected override void Dispose(bool disposing) {
context?.Dispose();
base.Dispose(disposing);
}
public IQueryable<Event> GetAllEvent() {
return Query();
}
public async Task<IHttpActionResult> PostEvent(Event item) {
var coordinator = context.Coordinators.Find(item.Coordinator.Id);
item.Coordinator = coordinator;
Event current = await InsertAsync(item);
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
}
从客户端发布数据按预期工作,我有一个带有正确数据的Coordinator表:
Posting data from the client works as expected, I have a Coordinator table with the right data:
ID Name Points IsActive Version CreatedAt UpdatedAt Deleted
cdf96b0f93644f1e945bd16d63aa96e0 John Smith 10 True 0x00000000000007D2 04/09/2015 09:15:02 +00:00 04/09/2015 09:15:02 +00:00 False
f216406eb9ad4cdcb7b8866fdf126727 Rebecca Jones 10 True 0x00000000000007D4 04/09/2015 09:15:30 +00:00 04/09/2015 09:15:30 +00:00 False
与第一个协调员相关的事件:
And a Event associated to the first Coordinator:
Id EventDate Attendees Location_Name Location_Address1 Location_Address2 Location_City Location_County Location_PostCode Version CreatedAt UpdatedAt Deleted Coordinator_Id
961abbf839bf4e3481ff43a214372b7f 04/11/2015 09:00:00 0 O2 Arena Peninsula Square London SE10 0DX 0x00000000000007D6 04/09/2015 09:18:11 +00:00 04/09/2015 09:18:11 +00:00 False cdf96b0f93644f1e945bd16d63aa96e0
这一切看起来都不错,我的两个问题是事件的获取,其中既不返回Coordinator
和Location
对象,而EventController的Get的Json就是这样:
At this point all looks good, my 2 problems are with the Get of the Event, where both Coordinator
and Location
objects are not returned and the Json of my EventController's Get is simply this:
[{"id":"961abbf839bf4e3481ff43a214372b7f","attendees":0,"eventDate":"2015-11-04T09:00:00Z"}]
所以我的两个问题是:
1)服务器上的EventController
正确加载了Location对象,如果返回之前中断,我可以看到正确加载的属性,对我来说这看起来像是Json序列化问题,但是我已经尝试更改串行器的配置(在WebApiConfig
上)没有太大影响,我尝试的最后一个选项是MaxDepth
,但仍然没有返回Location对象.
1) The Location object is loaded correctly by the EventController
on the server, I can see the properties correctly loaded if I break before returning, what for me looks like a Json serialization problem, but I already tried to change the serializer's configuration (on WebApiConfig
) without much effect, the last option I tried was the MaxDepth
but still the Location object is not returned.
2)我根本没有在服务器上加载过的Coordinator对象,甚至是ID(也没有正确地存储在表中)也没有加载,因此我无法强制加载整个对象,当然也不会将其返回给客户.
2) The Coordinator object I not loaded on the server at all, not even the Id (that is correctly stored on the table) so I cant force the load of the entire object, and of course it isn't returned to the client.
对我在这里做错的任何想法吗?
Any ideas on what I am doing wrong here?
预先感谢
克莱顿·洛瓦托(Claiton Lovato)
Claiton Lovato
推荐答案
这是TableController的默认行为. 为了以一种时尚的方式实现您要寻找的东西,您应该在控制器中实现OData $ expand .
This is default behavior for TableController. In order to achieve what you're looking for, in a fashion way, you should implement OData $expand in your controller.
This article provides a good walk-throughout for the solution
Retrieving data from 1:n relationship using .NET backend Azure Mobile Services
作为进一步的扩展,我实现了一个自定义属性,您可以在控制器方法中使用该属性来指定客户端可以请求扩展的属性.您可能不希望总是返回所有子关系(扩展的对象)
As further extension, I've implemented a custom attribute that you can use in your controller methods to specify which properties the client can request to expand. You may not want to always returned all child relationships (expanded objects)
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class ExpandablePropertyAttribute : ActionFilterAttribute
{
#region [ Constants ]
private const string ODATA_EXPAND = "$expand=";
#endregion
#region [ Fields ]
private string _propertyName;
private bool _alwaysExpand;
#endregion
#region [ Ctor ]
public ExpandablePropertyAttribute(string propertyName, bool alwaysExpand = false)
{
this._propertyName = propertyName;
this._alwaysExpand = alwaysExpand;
}
#endregion
#region [ Public Methods - OnActionExecuting ]
public override void OnActionExecuting(HttpActionContext actionContext)
{
base.OnActionExecuting(actionContext);
var uriBuilder = new UriBuilder(actionContext.Request.RequestUri);
var queryParams = uriBuilder.Query.TrimStart('?').Split(new char[1] { '&' }, StringSplitOptions.RemoveEmptyEntries).ToList();
int expandIndex = -1;
for (var i = 0; i < queryParams.Count; i++)
{
if (queryParams[i].StartsWith(ODATA_EXPAND, StringComparison.Ordinal))
{
expandIndex = i;
break;
}
}
if (expandIndex >= 0 || this._alwaysExpand)
{
if (expandIndex < 0)
{
queryParams.Add(string.Concat(ODATA_EXPAND, this._propertyName));
}
else
{
queryParams[expandIndex] = queryParams[expandIndex] + "," + this._propertyName;
}
uriBuilder.Query = string.Join("&", queryParams);
actionContext.Request.RequestUri = uriBuilder.Uri;
}
}
#endregion
}
我以这种方式在我的控制器中使用:
Which I use in my controller in this way:
[ExpandableProperty("Documents", false)]
public IQueryable<ClientActivity> GetAllClientActivities()
{
return Query();
}
这篇关于Azure移动服务TableController不返回内部对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!