实现具有循环依赖关系和可加载列表的Web API

时间:2013-10-07 09:09:05

标签: c# .net entity-framework asp.net-web-api odata

如何在WebAPI中实现这种“智能”GET?我有2个课程,我想从我的服务中获得。让我们说它的书店与书籍对象有关。

public class Book
{
    Guid Id { get; set; }
    string Title { get; set; }
    Store Store { get; set; }
}

public class Store
{
    Guid Id { get; set; }
    string Title { get; set; }
    string Owner { get; set; }
    IEnumerable<Book> Books { get; set; }
}

我在代码中有SQL Server和EntityFramework适配器的后端。我应该如何在我需要它之后返回书籍列表(请求它),就像OData一样? 正如您所看到的,我有循环依赖,这使我的JSON序列化程序显示错误。我解决它:

config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling  = Newtonsoft.Json.ReferenceLoopHandling.Serialize; 
config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;

但序列化了所有数据,我的回复是巨大的,这对我的Windows Phone应用程序来说并不好。在某些情况下,我只需要Store对象,但在其他情况下,我需要Store以及所有引用的书籍。

在控制器中,我使用[Queryable]属性来使用OData查询。 附:我无法创建更多的Web方法,如GetBooks,GetStore等。它应该是一种方法。

我怎样才能解决我的问题?

2 个答案:

答案 0 :(得分:1)

  

我怎样才能解决我的问题?

不要从API操作方法中返回实体。

相反,返回模型。

所以不要这样:

public IEnumerable<Store> GetStores()
{
    using (var db = new MyDbContext())
    {
        return db.Stores;
    }
}

做这样的事情:

public IEnumerable<StoreModel> GetStores()
{
    using (var db = new MyDbContext())
    {
        var entities = db.Stores;
        return entities.Select(x => new StoreModel
        {
            Id = x.Id,
            Title = x.Title,
            Owner = x.Owner,
            Books = x.Books.Select(y => new BookModel
            {
                Id = y.Id,
                Title = y.Title,
                StoreId = x.Id,
            }),
        });
    }
}

通过这种方式,您可以消除循环依赖图。 Book不再引用Store,仅引用StoreId

答案 1 :(得分:0)

你需要让它成为超媒体驱动的。书籍和商店可以被认为是不同的资源。当针对特定书籍发出GET请求时,如@danlugwig建议的那样,您可以返回书籍模型以及相应商店的URI。消费者可以使用此URI来检索商店详细信息。同样适用于商店资源。