Entity Framework 核心 - 不在

Entity Framework Core - Not In

我正在尝试在 EF Core 中复制一个 SQL 语句,但似乎无法找到一种方法来设置场景,我有以下 table 结构

插槽 -> SlotInstance -> SlotInstanceUser (一个Slot可以有多个SlotInstance,一个SlotInstance可以有多个SlotInstanceUser)

当用户注册 SlotInstance 时,会在 SlotInstanceUsers 中创建一条记录,存储 SlotInstanceId 和 UserId - 一切都很好。

我可以编写 SQL 来获取用户尚未注册的插槽实例列表,例如

    SELECT
        S.StartDate, S.EndDate, S.StartTime, S.EndTime, S.DayOfWeek,
        SI.Date
    FROM
        Slot S WITH (NOLOCK)
    INNER JOIN
        SlotInstance SI WITH (NOLOCK) ON S.Id = SI.SlotId
    WHERE
        SI.ID not in (  
                        SELECT 
                            SlotInstanceId 
                        FROM 
                            SlotInstanceUser SIU WITH (NOLOCK) 
                        WHERE 
                            SIU.UserId = @UserID
                    )   
    ORDER BY
        SI.Date

但我似乎无法在 EF 核心中复制它 - 我错过了什么?

您可以使用与 SQL 查询几乎相同的方式编写 LINQ 查询。请记住,在 LINQ 中,select 是最后一个,变量(别名)是强制性的,SQL NOT IN 的等价物是 !Contains。例如

var query =
from s in db.Slots
join si in db.SlotInstances on s.Id equals si.SlotId
where !(from siu in db.SlotInstanceUsers
        where siu.UserId == userId)
        select siu.SlotInstanceId).Contains(si.Id)
orderby si.Date
select new
{
    s.StartDate, s.EndDate, s.StartTime, s.EndTime, s.DayOfWeek,
    si.Date       
};

但在 EF Core 中,您有更多选择,尤其是对于联接,因为通常关系(和关联的联接)是用导航属性封装的。因此,您用 EF Core/C# terms 中的单词描述的模型类似于

public class Slot
{
    public int Id { get; set; }
    // Other properties...
    public ICollection<SlotInstance> SlotInstances { get; set; }
}

public class SlotInstance
{
    public int Id { get; set; }
    // Other properties...
    public Slot Slot { get; set; }
    public ICollection<SlotInstanceUser> SlotInstanceUsers { get; set; }
}

public class SlotInstanceUser
{
    public int Id { get; set; }
    // Other properties...
    public SlotInstance SlotInstance { get; set; }
}

查询就像

var query =
from s in db.Slots
from si in s.SlotInstances
where !si.SlotInstanceUsers.Any(siu => siu.UserId == userId)
orderby si.Date
select new
{
    s.StartDate, s.EndDate, s.StartTime, s.EndTime, s.DayOfWeek,
    si.Date       
};

(这实际上转化为 SQL NOT EXISTS,但这不是必需的)。

如果您不需要投影,而只是用户尚未注册的插槽实例(带有插槽信息),那么它就是简单的

var query = db.SlotInstances
    .Include(si => si.Slot)
    .Where(si => !si.SlotInstanceUsers.Any(siu => siu.UserId == userId))