如何在 Linq to SQL Navigation 属性 Generated Query 中使用 Left 而不是 Inner Join

How to Get Left Instead of Inner Join in Linq to SQL Navigation Property Generated Query

当我从 Linq 中的父对象 select 到 SQL 时,我得到了父对象 table 中的所有记录。但是,当我还 select 导航 属性(来自具有 1:1 关系和共享主键的扩展 table)时,我只会得到具有该导航的记录 属性人口稠密。如何使用导航 属性 从父项获取所有记录,而不管子项是否已填充? (即左连接而不是内部连接)? Linq to SQL 导航属性可以做到这一点,还是手动加入是唯一的选择? this post says it should be possible, and this post 上的一个建议答案说 Entity Framework 可以处理它,但我无法让它与 Linq 一起工作到 SQL.

查询次数:

        TestDataContext repository = new TestDataContext();

        // No navigation property selected, returns all records from Persons
        var result = repository.Persons.Select(x => new { x.PersonID, x.Name });
        // Navigation property selected, returns only persons having a record in PersonExtensions table
        var result1 = repository.Persons.Select(x => new { x.PersonID, x.Name, x.Extension.Height });

这是域名 类:

[Table(Name = "Persons")]
public class Person
{
    private System.Data.Linq.EntityRef<PersonExtension> _extension = new System.Data.Linq.EntityRef<PersonExtension>();

    [Association(Name = "Persons_PersonExtensions", Storage = "_extension", ThisKey = "PersonID", OtherKey = "PersonID", IsForeignKey = true)]
    public PersonExtension Extension
    {
        get
        {
            return _extension.Entity;
        }
        set
        {
            _extension.Entity = value;
        }
    }

    [Column(Name = "PersonID", DbType = "int NOT NULL IDENTITY", IsPrimaryKey = true, IsDbGenerated = true, CanBeNull = false, UpdateCheck = System.Data.Linq.Mapping.UpdateCheck.Never)]
    public int PersonID { get; set; }

    [Column(Name = "Name")]
    public string Name { get; set; }

    [Column(Name = "Gender")]
    public string Gender { get; set; }
}

[Table(Name = "PersonExtensions")]
public class PersonExtension
{
    private System.Data.Linq.EntityRef<Person> _person = new System.Data.Linq.EntityRef<Person>();

    [Association(Name = "Persons_PersonExtensions", Storage = "_person", ThisKey = "PersonID", OtherKey = "PersonID", IsForeignKey = true)]
    public Person Person
    {
        get
        {
            return _person.Entity;
        }
        set
        {
            _person.Entity = value;
        }
    }

    [Column(Name = "PersonID", DbType = "int NOT NULL", IsPrimaryKey = true, CanBeNull = false, UpdateCheck = System.Data.Linq.Mapping.UpdateCheck.Never)]
    public int PersonID { get; set; }

    [Column(Name = "Height ")]
    public int? Height { get; set; }
}

和数据上下文:

[Database]
public class TestDataContext:DataContext
{
    public TestDataContext() : base(@"Data Source=localhost; Initial Catalog = Test; Integrated Security = True")
    {
        this.CommandTimeout = 600;
    }

    public Table<Person> Persons;
    public Table<PersonExtension> PersonExtensions;
}

以下是 table 定义:

CREATE TABLE [dbo].[Persons](
    [PersonID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](50) NULL,
    [Gender] [nchar](10) NULL,
 CONSTRAINT [PK_Persons] PRIMARY KEY CLUSTERED 
(
    [PersonID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]


CREATE TABLE [dbo].[PersonExtensions](
    [PersonID] [int] NOT NULL,
    [Height] [int] NULL,
 CONSTRAINT [PK_PersonExtensions] PRIMARY KEY CLUSTERED 
(
    [PersonID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[PersonExtensions]  WITH CHECK ADD  CONSTRAINT [FK_PersonExtensions_Persons] FOREIGN KEY([PersonID])
REFERENCES [dbo].[Persons] ([PersonID])
GO

ALTER TABLE [dbo].[PersonExtensions] CHECK CONSTRAINT [FK_PersonExtensions_Persons]
GO

非常感谢任何帮助!!

注意:以上问题已从原始问题稍作修改,以更清楚地表明目标是使用导航属性。

zzz 替换为身高类型。

var result1 = repository.Persons.Select(x =>
    new { x.PersonID, x.Name, x.Extension == null ? (zzz?)null : x.Extension.Height });

更新

基于LINQ to SQL Left Outer Join

var query = from person in repository.Persons
            join extension in repository.Extensions
                on person.ExtensionId equals extension.ExtensionId into g
            from x in g.DefaultIfEmpty() // Creates a LEFT OUTER JOIN.
            select new
            {
                person.PersonID,
                person.Name,
                Height = x == null ? (int?) : x.Height
            };

var result = query.ToArray();

Linq 中的左连接似乎可以 SQL 导航属性,但无法按照我设置的方式设置对象。相反,"extension" table 的 id 必须不同于 "main" table 的 id,并且 "main" table 必须包含对扩展 ID table 的可空(例如 int?)引用。正是变量可以为 null 的事实告诉 Linq SQL 创建左连接而不是内部连接。当然,如果我尝试在两个 table 中使用相同的键,那是不可能的,因为主 table 的 id 必须是 [=22= 中的不可空字段].

我是根据 this post 想出来的。

不幸的是,这也很混乱,但我现在很确定,如果我想调用导航属性来生成左连接,这是唯一的选择。