Linq to sql 如何在Linq to SQL导航属性生成的查询中使用左键而不是内部联接

Linq to sql 如何在Linq to SQL导航属性生成的查询中使用左键而不是内部联接,linq-to-sql,left-join,inner-join,navigation-properties,Linq To Sql,Left Join,Inner Join,Navigation Properties,当我从Linq to SQL中的父对象中进行选择时,我将获得父表中的所有记录。但是,当我同时选择导航属性时(从具有1:1关系和共享主键的扩展表中),我只会得到填充了该导航属性的记录。如何使用navigation属性从父级获取所有记录,而不管是否填充了子级?(即左连接而不是内连接)?Linq到SQL导航属性可以做到这一点吗,或者手动连接是唯一的选项吗?关于的一个建议答案说这应该是可能的,并说实体框架将处理它,但我无法让它与Linq to SQL一起工作 查询: TestDataCo

当我从Linq to SQL中的父对象中进行选择时,我将获得父表中的所有记录。但是,当我同时选择导航属性时(从具有1:1关系和共享主键的扩展表中),我只会得到填充了该导航属性的记录。如何使用navigation属性从父级获取所有记录,而不管是否填充了子级?(即左连接而不是内连接)?Linq到SQL导航属性可以做到这一点吗,或者手动连接是唯一的选项吗?关于的一个建议答案说这应该是可能的,并说实体框架将处理它,但我无法让它与Linq to 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; }
}
任何帮助都将不胜感激


注意:上面的问题已从原来的问题稍作修改,以便更清楚地说明其目的是使用导航属性。

zzz替换为高度类型

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

更新 基于:


看起来Linq到SQL导航属性中的左连接是可能的,但是对象不能像我设置我的那样设置。相反,“扩展”表的id必须不同于“主”表的id,“主”表必须包含对扩展表id的可空引用(例如int?)。事实上,这个变量是可以为null的,它告诉Linq to SQL创建一个左连接,而不是一个内部连接。当然,如果我尝试在两个表中使用相同的键,那是不可能的,因为主表的id必须是该表中不可为null的字段

我是根据我的经验得出这个结论的


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

Hmm。我刚刚尝试过-将查询行更改为以下内容(命名为匿名类型的Height变量),但我仍然只得到结果集中PersonExtensions中存在的记录:var result1=repository.Persons.Select(x=>new{x.PersonID,x.Name,Height=x.Extension==null?(int?)null:x.Extension.Height});不幸的是,仍然只有两个表中存在的一条记录返回。@user756366就这样。谢谢!这确实有效。不幸的是,我想我确实需要让这个问题保持开放。。。因为我真正期待的是一种使用导航属性并让linq自动生成左连接的方法。相反,此解决方案会忽略导航属性并手动创建联接,这在许多情况下都可以工作,但很难与动态SQL和用户生成的查询一起使用。我非常感谢你的帮助!非常感谢你!抱歉,无法标记为答案!你有不可为空的ID?天哪,怪不得它对你不起作用。我完全不明白为什么可以对另一个表进行可为空的逻辑引用,但仍然是不可为空的ID字段。这没有任何意义,表明存在一个非常巨大的设计问题。我们希望这样做,因为我们有一个主表已经存在很长时间了,我们希望添加一个扩展表,其中包含更多字段,每个客户自定义,以允许他们添加他们需要的字段。我们关心的是强制执行一条规则,即对于原始表中的每条记录,该表中都必须有一条记录,因为这是一个复杂的现有系统,虽然我们确实计划捕获所有插入记录的位置,但我们不能100%确定是否能够捕获所有位置。我们希望更改不会有丢失现有报告/查询中记录的风险。
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
var result1 = repository.Persons.Select(x =>
    new { x.PersonID, x.Name, x.Extension == null ? (zzz?)null : x.Extension.Height });
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();