如何使用自定义相等性检查通过 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
模型有一个 Equals
和 GetHashCode
覆盖仅在标记上的相等性测试:
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]
我加入了两个 tables:
用户 > 设备
一个用户可以在 FK 上加入多个设备 user_ID。设备 table 有一个主键 ID。但是该设备也有一个被认为是唯一的令牌。
我正在尝试 select 没有令牌的用户:
IQueryable<User> users = DbContext.Users.Where(u => u.ID == _id && !u.Devices.Contains(device));
这里传入的 device
有一个标记,Device
模型有一个 Equals
和 GetHashCode
覆盖仅在标记上的相等性测试:
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]