在我当前的项目中,我首先使用 WebAPI 和 EntityFramework 模型。经过一些调查后,似乎我必须使用LazyLoading
才能加载相关实体。
我在很多博客中都读过,在服务中使用LazyLoading
会导致性能和序列化问题 - 所以我想尽可能避免使用它。
关于如何在不创建POCO对象的情况下实现此目的的任何建议?
答案 0 :(得分:1)
您问题的简单答案是 - 使用.Include()
。
作为示例:假设您有一个Customer
对象,该对象具有关联的ReferredBy
对象,该对象引用另一个客户。在您的应用程序中,您希望返回Customer
的列表以及引用每个Customer
的关联[HttpGet]
public IQueryable<Customer> Customers() {
return db.Customers.OrderBy(c => c.LastName).Top(10);
}
。
您的WebAPI方法可能类似于:
A
当序列化程序得到此信息时,您可能会遇到各种错误,您可以阅读更多关于in this article的错误。但实质上,它来自两件事:
B
表示B
,而A
表示Global.asax
- 所以每次我序列化一个,我再次序列化另一个一个孩子。这会产生无限循环。我不会涉及所有细节或其他问题 - 我已经给了你一篇深入研究的文章。相反,这是我在我的应用程序中解决问题的方式:
在.cs
或其中一个config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Ignore;
文件中,这些文件是作为配置的一部分加载的,请使用以下设置:
MergeOption
这告诉JSON.net 不序列化参考循环。
将DataContext
及其Collection
个属性中的MergeOption.NoTracking
设置为.tt
。在我的应用程序中,我通过编辑创建DataContext
:
MergeOption _defaultMergeOption = MergeOption.AppendOnly;
public <#=code.Escape(container)#>() : this("name=<#=container.Name#>") { }
public <#=code.Escape(container)#>(String connectionString) : base(connectionString) {
<# if (!loader.IsLazyLoadingEnabled(container)) { #>
this.Configuration.LazyLoadingEnabled = false;
<# } #>
this.Configuration.ProxyCreationEnabled = false;
_defaultMergeOption = MergeOption.NoTracking;
}
文件来完成此操作
首先,找到创建构造函数的行,然后更改为:
<# foreach (var entitySet in container.BaseEntitySets.OfType<EntitySet>()) { #>
找到以:
开头的行<# foreach (var entitySet in container.BaseEntitySets.OfType<EntitySet>()) { #>
<#= Accessibility.ForReadOnlyProperty(entitySet)#> ObjectQuery<<#=typeMapper.GetTypeName(entitySet.ElementType)#>> <#=code.Escape(entitySet)#> {
get {
var set = (((IObjectContextAdapter)this).ObjectContext).CreateObjectSet<<#=typeMapper.GetTypeName(entitySet.ElementType)#>>();
set.MergeOption = _defaultMergeOption;
return set;
}
}
<# }
现在编辑下几行说:
DataContext
这样做会为您MergeOption.NoTracking
提供一个构造函数,该构造函数可以将所有集合默认为ProxyCreation
,并自动禁用LazyLoading
和DataContext
。当您创建var db = new MyDataContext("ConnectionStringGoesHere");
的实例以进行拉取时,您现在可以简单地说:
[HttpGet]
public IQueryable<Customer> Customers() {
return db.Customers.Include("ReferredBy")
.OrderBy(c => c.LastName).Top(10);
}
鉴于上述情况,您的新WebAPI方法变得如此简单:
.Include()
[{
Id: 1,
FirstName: 'Frank',
LastName: 'Abba',
ReferredBy: {
Id: 4,
FirstName: 'Bob',
LastName: 'Jones',
ReferredBy: null
}
}, {
Id: 4,
FirstName: 'Bob',
LastName: 'Jones',
ReferredBy: null
}
}]
将子记录作为初始SQL语句的一部分加载(一次命中总数),Serializer将忽略后引用,允许您生成类似于以下内容的JSON:
{{1}}