当包含子元素时,LINQ查询返回的结果较少

时间:2016-03-25 19:40:41

标签: c# entity-framework linq

我想做一个返回Parent表的所有记录的LINQ查询,并包含Child(如果适用)。我知道我可以使用DefaultIfEmpty()进行LINQ连接,但是我必须输出一个ViewModel。我想获得实际父类的IQuerable<Parent>

所以,如果我有这些课程:

public class Parent
{
    [Key]
    public int ParentId {get; set;}
    public string ParentName {get; set;}

    public int? MyChildId {get; set;}

    [ForeignKey("MyChildId")]
    public virtual Child MyChild {get; set;}

    public bool IsActive {get;set;}
}

public class Child
{
    public int ChildId {get;set;}
    public string ChildName {get;set;}
}

在LINQPad中,如果我这样做:

var results = db.Parent.Where(ra => ra.IsActive);
results.Dump();

我得到111条记录。

如果我这样做:

var results = db.Parent.Where(ra => ra.IsActive);

var results2 = (from r in results
                select new
                {
                    ParentId = r.ParentId,
                    ParentName = r.ParentName,
                    MyChildId = r.MyChildId
                });
results2.Dump();

我还收到111条记录。

但如果我这样做:

var results = db.Parent.Where(ra => ra.IsActive);

var results2 = (from r in results
                select new
                {
                    ParentId = r.ParentId,
                    ParentName = r.ParentName,
                    MyChildId = r.MyChildId,
                    IsActive = r.IsActive,
                    MyChildName = r.MyChild == null ? null : r.MyChild.ChildName
                });
results2.Dump();

我只得到50条记录。这些是有孩子的50条Parent条记录。如果他们没有孩子,他们就不会回来。

生成的SQL如下所示:

SELECT 
    [Extent1].[ParentId] AS [ParentId], 
    [Extent1].[ParentName] AS [ParentName], 
    [Extent1].[IsActive] AS [IsActive],
    [Extent2].[ChildName] AS [ChildName]
    FROM  [dbo].[Parent] AS [Extent1]
    INNER JOIN [dbo].[Child] AS [Extent2] ON [Extent1].[MyChildId] = [Extent2].[ChildId]
    WHERE [Extent1].[IsActive] = 1

如何获得包含所有111条Parent条记录的结果集,即使它们没有子级,但是包含Child元素,如果它们在那里?

更新 所以,我可能会撒谎。为了简单起见,我发布了上面的内容,但为了防止它有用,下面是代码所做的更接近的示例:

public class Parent
{
    [Key]
    public int ParentId {get; set;}
    public string ParentName {get; set;}

    public int? MyChildId {get; set;}

    [ForeignKey("MyChildId")]
    public virtual Child MyChild {get; set;}

    [ForeignKey("MyChildId")]
    public virtual StepChild MyStepChild {get; set;}

    public bool IsActive {get;set;}
}

public class Child
{
    public int ChildId {get;set;}
    public string ChildName {get;set;}
}

public class StepChild
{
    public int StepChildId {get;set;}
    public string StepChildName {get;set;}
}

3 个答案:

答案 0 :(得分:0)

有时候很难分辨EF幕后发生的事情,你可能会遇到一些非显而易见的行为,我通常在这种情况下做的事情 - 检查实际生成的SQL查询,并调整LINQ查询直到它在逻辑上等同于我期望的查询。 这不是最好的方法,因为它取决于可以改变的实现细节,但有时它是克服EF错误的唯一方法。 您可以使用数据库调用的ObjectQuery或EF logging and interception来获取实际的SQL查询

答案 1 :(得分:0)

你需要两个单独的FK属性吗? personAssigneeId和另一个int? organizationAssigneeId。这些FK指向两个完全不同的实体。如果为两个独立的实体重用相同的FK,则EF无法正常工作,每个实体需要一个FK。

答案 2 :(得分:0)

默认情况下(或要求)您的外键不可为空,因此您需要告诉EF它应该是可选的。要实现它,您需要覆盖以下modelBuilder方法:

public class MyContext : DbContext
    {
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
        }   
    }

并配置您的Entity外键:

modelBuilder.Entity<Parent>().HasOptional(e => e.MyChild).WithMany();

您可以在此处查看详细信息:http://blog.staticvoid.co.nz/2012/7/17/entity_framework-navigation_property_basics_with_code_first