LINQ LEFT JOIN on Nullable <int> </int>

时间:2015-03-09 06:42:00

标签: c# linq entity-framework join

我有两张桌子:

Project(
    ProjectID       INT,
    Name            VARCHAR(200),
    AssignedUserID  INT NULL
)
User(
    UserID      INT,
    LastName    VARCHAR(50),
    FirstName   VARCHAR(50)
)

我使用的是Entity Framework Database-First方法。所以在我的模型中:

Class Project{
    public int ProjectID;
    public string Name;
    public Nullable<int> AssignedUserID;
}

Class User{
    public int UserID;
    public string LastName;
    public string FirstName;
}

我想查询所有PROJECT及其分配的用户:

SELECT
    p.ProjectID,
    p.Name,
    u.LastName,
    u.FirstName
FROM Project p
LEFT JOIN Users u ON u.UserID = p.AssignedUserID

翻译为Linq:

var projectDetails =
    from p in context.Project
    join u in context.User
        on p.AssignedUserID equals u.UserID into lj
    from x in lj.DefaultIfEmpty()
        select new {
            ProjectID = p.ProjectID,
            ProjectName = p.Name,
            UserLastName = u.LastName,
            UserFirstName = u.FirstName
        }

但是,我收到了错误:

  

join子句中某个表达式的类型不正确。   呼叫&#39;加入&#39;

时,类型推断失败

我已经在 int? and int comparison when LEFT OUTER JOIN in Linq issue 上尝试了两种解决方案,但它仍然给我这些错误:

使用解决方案:(int)(p.AssignedUserID ?? default(int))

  

LINQ to Entities无法识别方法&#39; Int32 ToInt32(Int32)&#39;   方法,并且此方法无法转换为商店表达式。

使用解决方案GetValueOrDefault()

  

LINQ to Entities无法识别方法&#39; Int32   GetValueOrDefault(的Int32)&#39;方法,这个方法无法翻译   进入商店表达。

您如何LEFT JOINNullable<int>上的int

3 个答案:

答案 0 :(得分:7)

当我必须在可空字段上进行加入时,我就会这样做

原Linq:

var projectDetails =
    from p in context.Project
    join u in context.User
        on p.AssignedUserID equals u.UserID into lj
    from x in lj.DefaultIfEmpty()
        select new {
            ProjectID = p.ProjectID,
            ProjectName = p.Name,
            UserLastName = u.LastName,
            UserFirstName = u.FirstName
        }

修改后的Linq:

var projectDetails =
    from p in context.Project
    join u in context.User
        on new {User = p.AssignedUserID} equals new {User = (int?)u.UserID} into lj
    from x in lj.DefaultIfEmpty()
        select new {
            ProjectID = p.ProjectID,
            ProjectName = p.Name,
            UserLastName = x.LastName,
            UserFirstName = x.FirstName
        }

问题是你正在尝试使用int?加入一个int,它会给你错误信息,将UserId的int转换为可以为null的int,将解决你的问题。

答案 1 :(得分:2)

你实际上做了很多EF应该为你做的工作(这种情况很多,尤其是join)。

您需要Project课程的导航属性,而不仅仅是您现在拥有的FK:

编辑:为EF Database-First更新了以下POCO(即使用partial类)。

// generated code
public partial class Project
{
    public int ProjectId { get; set; }
    public string Name { get; set; }
    public int? AssignedUserId { get; set; }
}

public class User
{
    public int UserId { get; set; }
    public string LastName { get; set; }
    public string FirstName { get; set; }
}

// your code
public partial class Project
{
    [ForeignKey("AssignedUserId")]
    public User User { get; set; }
}

请注意,每次重新生成partial类时,您必须记住在Project类的生成版本上添加partial关键字,但这仍然更好,因为 - 通过将您的添加保留在单独的partial类声明 - var projectDetails = from p in context.Projects select new { p.ProjectId, p.Name, p.User.LastName, p.User.FirstName }; 关键字是唯一的,您必须记住在生成的类中进行更改。

所以您的查询只是以下内容:

Console.WriteLine(projectDetails.ToString());

让我们看看它是什么样的:

SELECT
    [Extent1].[ProjectId] AS [ProjectId],
    [Extent1].[Name] AS [Name],
    [Extent2].[LastName] AS [LastName],
    [Extent2].[FirstName] AS [FirstName]
    FROM [Projects] AS [Extent1]
    LEFT OUTER JOIN [Users] AS [Extent2] ON [Extent1].[AssignedUserId] = [Extent2].[UserId]

这会产生以下SQL:

{{1}}

这似乎正是你想要的。

答案 2 :(得分:1)

如果联接中的任何列属于Nullable类型,我们需要使用.Value获取itts实际值,如下所示: -

    join u in context.User
        on p.AssignedUserID.Value equals u.UserID into lj

或者您也可以这样做: -

join u in context.User
            on new { p.AssignedUserID } equals new { AssignedUserID = u.UserID } into lj