如何使用自定义相等性检查通过 EF Core 查询集合?

How can I query collection with EF Core using custom equality check?

我加入了两个 tables:

用户 > 设备

一个用户可以在 FK 上加入多个设备 user_ID。设备 table 有一个主键 ID。但是该设备也有一个被认为是唯一的令牌。

我正在尝试 select 没有令牌的用户:

IQueryable<User> users = DbContext.Users.Where(u => u.ID == _id && !u.Devices.Contains(device));

这里传入的 device 有一个标记,Device 模型有一个 EqualsGetHashCode 覆盖仅在标记上的相等性测试:

public bool Equals(Device comp)
{
  return comp.DeviceId.Equals(this.DeviceId);
}

因此,如果我先 select 用户,然后在代码中查询设备集合,我可以检查用户是否尚未关联设备:

IQueryable<User> users = DbContext.Users.Where(u => u.ID == _id);

User user = users.First();

if (!user.Devices.Contains(device))
{
  ...Contains here has compared devices based only on device token        
}

但是 EF Core 构造查询:

SELECT TOP(1) [u].[ID], ...{other user properties cut for brevity}
      FROM [Users] AS [u]
      WHERE ([u].[ID] = @__id_0) AND @__8__locals1_device_1_Id NOT IN (
          SELECT [d].[Id]
          FROM [Device] AS [d]
          WHERE [u].[ID] = [d].[User_ID]
      )

在我看来,我只能根据设备的 ID 属性 来测试是否相等...

是否有任何方法可以构建与代码 Equality/GetHashCode 检查匹配的 EF Core 查询,或者我是否必须在代码中执行此操作?

我转载了你的案例。请在下面找到代码。并查看评论以获取解释。

// user class
public partial class tempu
{
    public int id { get; set; }
    [StringLength(50)]
    public string name { get; set; }
    public List<tempd> tempds { get; set; }
}

// device class
public partial class tempd
{
    public int? token { get; set; }
    public int? uid { get; set; }
    [StringLength(50)]
    public string name { get; set; }
    public int id { get; set; }
    public tempu tempus { get; set; }
}

// context
modelBuilder.Entity<tempu>(entity =>
{
    entity.ToTable("tempu");
});

//// this is do the mapping of one to many
modelBuilder.Entity<tempd>(entity =>
{
    entity.ToTable("tempd")
    .HasOne(p => p.tempus)
    .WithMany(i => i.tempds)
    .HasForeignKey(b => b.uid);
});

// linq query
var results = _context.tempu
      .Where(t => t.tempds.Any(y => y.token == null)) //// this will check if device id can be null in any case, 
      .Include(s => s.tempds) //// this will do the join
      .ToList();

// generated sql
SELECT [t].[id], [t].[name]
FROM [tempu] AS [t]
WHERE EXISTS (
    SELECT 1
    FROM [tempd] AS [y]
    WHERE [y].[token] IS NULL AND ([t].[id] = [y].[uid]))
ORDER BY [t].[id]