使用EF从Azure移动服务检索父/子记录(包含列表的对象)

时间:2017-06-20 07:22:34

标签: c# entity-framework azure azure-mobile-services

我有.net 4.5.2测试应用程序在玩Azure移动服务,我尝试使用TableController存储数据。我的数据类型如下:

public class Run:EntityData
{
public int RunId { get; set; }
public DateTime? ActivityStarted { get; set; }
public DateTime? ActivityCompleted { get; set; }
public List<Lap> LapInformation { get; set; }

public Run()
{
    LapInformation = new List<Lap>();
}

}

public class Lap
{
    [Key]
    public int LapNumber { get; set; }
    public int CaloriesBurnt { get; set; }
    public double Distance {get; set;}
    //Some other basic fields in here
    public DateTime? LapActivityStarted { get; set; }
    public DateTime? LapActivityCompleted { get; set; }

    public Lap()
    {
}

在我的Startup课程中,我打电话:

    HttpConfiguration config = new HttpConfiguration();

    new MobileAppConfiguration()
        .UseDefaultConfiguration()
        .ApplyTo(config);

在我的MobileServiceContext类中:

public class MobileServiceContext : DbContext
{
    private const string connectionStringName = "Name=MS_TableConnectionString2";

    public MobileServiceContext() : base(connectionStringName)
    {
    }

    public DbSet<Run> Runs { get; set; }
    public DbSet<Lap> Laps { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.Add(
        new AttributeToColumnAnnotationConvention<TableColumnAttribute, string>(
            "ServiceTableColumn", (property, attributes) => attributes.Single().ColumnType.ToString()));
}

}

在我的控制器中,我有:

[MobileAppController]
public class RunController: TableController<Run>
{
    protected override void Initialize(HttpControllerContext controllerContext)
    {
        base.Initialize(controllerContext);
        MobileServiceContext context = new MobileServiceContext();
        DomainManager = new EntityDomainManager<Run>(context, Request);
    }

    public IList<Run> GetAllRuns()
    {
        var runs = context.Runs.Include("LapInformation").ToList();
        return runs;
}

public SingleResult<Run> GetRun(string id)
{
    return Lookup(id);
}

public async Task<IHttpActionResult> PostRun(Run run)
{
    Run current = await InsertAsync(run);
    return CreatedAtRoute("Tables", new { id = current.Id }, current);
}

public Task DeleteRun(string id)
{
    return DeleteAsync(id);
}

}

然后我可以POST fiddler中的201记录,该记录以{RunId: 1234, LapInformation:[{LapNumber:1,Distance:0.8, LapActivityStarted: "2017-06-19T00:00:00", LapActivityCompleted: "2017-06-19T00:00:00", CaloriesBurnt: 12}]} 和新创建的项目的位置进行响应。我发布的数据示例如下:

GET

然而,当我''该对象时,我只从Run中获取字段,而没有详细记录列表(Lap)。有什么我必须在实体框架中配置,以便当我从数据库获取运行记录时,它还获取并反序列化所有相关的详细记录?

希望这是有道理的。

修改 事实证明它正在拉回所有的圈数信息,但是当我将它返回给客户端时,这些信息就会丢失。

2 个答案:

答案 0 :(得分:1)

您可以使用自定义EF查询和Include()方法,而不是Lookup调用,最好是从System.Data.Entity命名空间获取函数的重载。

var runs = context.Runs.Include(r => r.LapInformation)

查看https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx

答案 1 :(得分:1)

AFAIK,您还可以使用$expand参数扩展您的收藏集,如下所示:

GET /tables/Run$expand=LapInformation

这是我的样本,您可以参考它:

enter image description here

您可以使用自定义ActionFilterAttribute标记您的操作,以便自动将$expand属性添加到您的查询请求中,如下所示:

// GET tables/TodoItem
[ExpandProperty("Tags")]
public IQueryable<TodoItem> GetAllTodoItems()
{
    return Query();
}

有关详细信息,请参阅adrian hall的书chapter3 relationships

  

编辑结果证明它正在撤回所有圈数信息,但当我将其返回给客户端时,该信息就会丢失。

我在移动客户端中定义了以下模型:

public class TodoItem
{
    public string Id { get; set; }
    public string UserId { get; set; }
    public string Text { get; set; }
    public List<Tag> Tags { get; set; }
}

public class Tag
{
    public string Id { get; set; }
    public string TagName { get; set; }
}

执行以下拉动操作后,我可以按如下方式检索标签:

await todoTable.PullAsync("todoItems", todoTable.CreateQuery());

注意:Tags数据是只读的,您只能更新ToDoItem表中的信息。

此外,正如Data Access and Offline Sync - The Domain Manager中提到的adrian hall:

  

我更喜欢单独处理表格并手动处理移动客户端上的关系管理。这会在移动客户端上产生更多代码,但通过避免大多数关系的复杂性使服务器更加简单。