在实体框架中我想只包括第一个子对象而不包括子对象(sub子)

时间:2015-05-12 09:04:58

标签: asp.net-mvc entity-framework entity-framework-4 linq-to-entities entity-framework-5

我有这两个类:

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下返回商品对象而不提供商品。

有人可以帮忙吗?

4 个答案:

答案 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);
}