我有这两个类:
public class BusinessesTBL
{
public string ID { get; set; }
public string FirstName { get; set; }
public string lastName { get; set; }
public ICollection<OffersTBL> OffersTBLs { get; set; }
}
public class OffersTBL
{
public int ID { get; set; }
public string Name { get; set; }
public int CatId { get; set; }
public string BusinessesTBLID { get; set; }
public virtual BusinessesTBL BusinessesTBLs { get; set; }
}
当我尝试根据CatId字段提供所有优惠时,我还需要返回BusinessesTBLs,但该方法还会根据每个BusinessesTBL obj返回优惠,我的代码是:
public IQueryable<OffersTBL> GetOffersTBLsCat(int id)
{
db.OffersTBLs.Include(s => s.BusinessesTBLs);
}
您可以看到错误的结果: http://priooffer.azurewebsites.net/api/OffersApi/GetOffersTBLsCat/4
正如您所看到的,它返回每个Business对象下的所有商品,而每个商品对象下的商品对象,我只希望在Business obj下返回商品对象而不提供商品。
有人可以帮忙吗?
答案 0 :(得分:10)
您已停用OffersTBLs上的延迟加载,使其成为非虚拟加载。如果激活延迟加载怎么办?像这样:
float: left;
然后,确保在序列化时不要调用/包含OffersTBLs。如果OffersTBLs仍在返回,那是因为您正在代码中的某处获取它们。如果发生这种情况,请编辑您的问题并粘贴所有代码,包括序列化逻辑。
答案 1 :(得分:7)
这是因为实体框架执行关系修正,这是当属于那里的对象存在于上下文中时自动填充导航属性的过程。因此,使用循环引用,即使禁用延迟加载,也可以无限地向下钻取导航属性。 Json序列化器正是这样做的(但显然它已被指示处理循环引用,因此它不会陷入无限循环中)。
诀窍是防止关系修复不断下降。关系修复依赖于上下文的var validator = $("#loginForm").validate({
errorClass: "error",
errorElement: 'span',
highlight: function (element, errorClass, validClass) {
$(element).parents("div.control-group").addClass(errorClass);
},
unhighlight: function (element, errorClass, validClass) {
$(element).parents(".error").removeClass(errorClass);
},
showErrors: function(map, list) {
this.defaultShowErrors(); // calls the default function
// after which we can add our changes
$('span.error').each(function(index) {
$(this).html('');
var img = $('<img id="dynamic">');
img.attr('src', "../images/inputerror.png");
$(this).append(img);
});
}
});
,它会缓存对象以跟踪其更改和关联。但是如果没有什么可追踪的话,就没有什么可以解决的了。您可以致电ChangeTracker
:
AsNoTracking()
除此之外,您还要在上下文中禁用延迟加载(通过设置db.OffersTBLs.Include(s => s.BusinessesTBLs)
.AsNoTracking()
),您将看到Json字符串中只填充了contextConfiguration.LazyLoadingEnabled = false
,并且OffersTBL.BusinessesTBLs
是空数组。
奖励是BusinessesTBL.OffersTBLs
提高了性能,因为更改跟踪器并不忙于跟踪EF实现的所有对象。实际上,您应该始终在断开连接的设置中使用它。
答案 2 :(得分:3)
由于OffersTBL与BusinessesTBL和BusinessesTBL与OffersTBL有关联,因此您可以无限循环抛出OffersTBL.BusinessesTBL.OffersTBL.BusinessesTBL等实体。
要控制实体的嵌套深度,我通常使用带有所需属性的辅助类。
对于BusinessesTBL
public class BusinessesTBLHelper
{
private BusinessesTBLHelper(BusinessesTBL o){
ID = o.ID;
FirstName = o.FirstName;
lastName = o.LastName;
OffersTBLids = new List<int>();
foreach(OffersTBL offersTbl in o.OffersTBLs){
OffersTBLids.Add(offersTbl.ID);
}
}
public string ID { get; set; }
public string FirstName { get; set; }
public string lastName { get; set; }
public IEnumerable<int> OffersTBLids { get; set; } //no references anymore
}
对于您的OffersTBL实体也一样。
public class OffersTBLHelper
{
private OffersTBLHelper(OffersTBL o){
ID = o.ID;
Name = o.Name;
CatId = o.CatId;
BusinessesTBLID = o.BusinessesTBLID;
BusinessesTBLs = new BusinessesTBLHelper(o.BusinessesTBLs);
}
public string ID { get; set; }
public string Name{ get; set; }
public intCatId{ get; set; }
public string BusinessesTBLID { get; set; }
public BusinessesTBLHelper BusinessesTBLs { get; set; }
}
在quering数据库上,您可以直接从queryresult创建新的helperobject:
public IEnumerable<OffersTBLHelper> GetOffersTBLsCat(int id)
{
return db.OffersTBLs.where(s => s.CatId == id).Select(x=> new OffersTBLHelper(x)).ToList();
}
现在您拥有了所有与TinessesTBLs一起提供的优惠TB。循环在这里停止,因为BusinessesTBLs下面没有OffersTBL。但是,它只有List中的ID才能进一步引用和识别。
答案 3 :(得分:-1)
假设对象不为null且只是空:
public IQueryable<OffersTBL> GetOffersTBLsCat(int id)
{
db.OffersTBLs.Include(s => s.BusinessesTBLs).Where(x => !x.BusinessesTBLs.OffersTBLs.Any());
}
编辑:在包含之前过滤:
public IQueryable<OffersTBL> GetOffersTBLsCat(int id)
{
db.OffersTBLs.Where(x => !x.BusinessesTBLs.OffersTBLs.Any())
.Include(s => s.BusinessesTBLs);
}