查找非多对多关系的实体
Find entities not in many-to-many relation
我可能看错了,但我在 EF Core 3.1 中有一个基本的多对多代码优先设置,其中 Department <-> DepartmentDay <-> Day。
modelBuilder.Entity<DepartmentDay>(entity =>
{
entity.HasKey(dd => new { dd.DepartmentId, dd.DayId });
entity.HasOne(dp => dp.Day)
.WithMany(p => p.DepartmentDays)
.HasForeignKey(d => d.DayId);
entity.HasOne(dp => dp.Department)
.WithMany(p => p.DepartmentDays)
.HasForeignKey(d => d.DepartmentId);
});
第一个问题:这种关系是可选的,我可以有几天不与部门联系吗?我需要这个,因为这与营业时间有关,并且希望有影响所有部门的通用日期,而不必与所有部门建立特定连接。但正如我一开始所说,我可能会以错误的方式看待这个问题。
第二个问题:如果第一个问题是真实有效的设置,我如何在 Linq 查询中获取那些未连接到部门的日子?
我目前拥有的是(编辑:将 allDays 从 Hashset 更改为 List。)
var allDays = await _context.Days.ToListAsync();
var allDepartmentDays = _context.DepartmentDays.Select(dd => dd.DayId).ToHashSet();
var genericDays = allDays.Where(d => !allDepartmentDays.Contains(d.Id));
还是在这里使用原始查询来提高性能更好?
SELECT Id
FROM Day
WHERE Id NOT IN (SELECT DayId FROM DepartmentDay)
编辑 2:包括整个数据模型
public class Department
{
public int Id { get; set; }
public int DepartmentNr { get; set; }
public string Service { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Address { get; set; }
public string Postal { get; set; }
public string City { get; set; }
public string Url { get; set; }
public string MapUrl { get; set; }
public DateTime Created { get; set; }
public string CreatedBy { get; set; }
public DateTime? Updated { get; set; }
public string UpdatedBy { get; set; }
public ICollection<DepartmentPeriod> DepartmentPeriods { get; set; }
public ICollection<DepartmentDay> DepartmentDays { get; set; }
}
public class DepartmentDay
{
public int DepartmentId { get; set; }
public int DayId { get; set; }
public Department Department { get; set; }
public Day.Models.Day Day { get; set; }
}
public class Day
{
public int Id { get; set; }
public int PeriodId { get; set; }
public string Service { get; set; }
public string City { get; set; }
public DateTime? Date { get; set; }
public DayOfWeek? DayOfWeek { get; set; }
public DateTime? OpenTime { get; set; }
public DateTime? CloseTime { get; set; }
public bool IsClosed { get; set; }
public string Description { get; set; }
public DateTime Created { get; set; }
public string CreatedBy { get; set; }
public DateTime? Updated { get; set; }
public string UpdatedBy { get; set; }
public ICollection<DepartmentDay> DepartmentDays { get; set; }
public virtual Period.Models.Period Period { get; set; }
}
modelBuilder.Entity<Day>(entity =>
{
entity.HasOne(d => d.Period)
.WithMany(p => p.Days)
.HasForeignKey(d => d.PeriodId);
});
还有一个关系没有包含在初始问题中,我的第一个问题的答案是Department 1-M DepartmentPeriod M-1 Period 1-1 Day。所以 Day table 中的某些日子与 DepartmentDay 无关,但仅与 Period 无关,对吗?
第一个问题:它是可选的吗?没有你的数据类型真的是一个棘手的问题,但假设你有正确的导航属性,你只需要指定导航属性,如果它们的键没有命名为 {DataType}Id,所以如果你这样命名它们就不是必需的,否则您必须指定要使用哪些外键字段以及哪些是键。如果您不指定关系,entity framework 将为您生成多对多关系的表。
第二个问题:
在性能方面,如果您能够编写一个好的查询,SQL 查询将始终优于您建议的查询,甚至
select a.id from [day] a left join departmentday b on a.id = b.dayid where b.dayid is null
即便如此,也可以表现得更好一些,
然而,就可测试性而言,sql 是一个问题,因为我们想要 运行 我们实体 dbcontext 的 InMemory 模型,然后你的 sql 通常至少不能执行。
所以问题是,如果您真的需要额外的性能,并且是否有可能编写一个 linq 查询,通过使其成为同一表达式的一部分而不是两个或更多表达式,从而有效地使 linq 引擎编写类似的查询.
在您的情况下,我可能会遗漏目前未提供的数据模型中的某些内容,但您似乎可以像这样获得您想要的内容:
_context.Days.Include(d => d.DepartmentDays).Where(!d.DepartmentDays.Any());
更新:
查看模型,似乎缺少一些模型工作,您正在寻找的投影可以按照建议的方式完成。
模型创建的更改/添加:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Department>()
.HasKey(k => k.Id);
modelBuilder.Entity<DepartmentDay>()
.HasKey(k => new { k.DayId, k.Department });
modelBuilder.Entity<Day>()
.HasOne(d => d.Period)
.WithMany(p => p.Days)
.HasPrincipalKey(k => k.PeriodId)
.HasForeignKey(d => d.Id);
//Notice your departmentid is not alone a foreign key in the relationship table, as departments can have one row per day
modelBuilder.Entity<DepartmentDay>()
.HasOne(a => a.Department)
.WithMany(b => b.DepartmentDays)
.HasPrincipalKey(p => p.Id)
.HasForeignKey(f => new { f.DepartmentId, f.DayId });
base.OnModelCreating(modelBuilder);
}
并且在上下文中我们可以使用以下方式进行此类查询:
public List<Day> GetDaysWithoutAnyDepartmentDays()
{
return Days
.Include(i => i.DepartmentDays)
.Where(x => !x.DepartmentDays.Any()
).ToList();
}
我可能看错了,但我在 EF Core 3.1 中有一个基本的多对多代码优先设置,其中 Department <-> DepartmentDay <-> Day。
modelBuilder.Entity<DepartmentDay>(entity =>
{
entity.HasKey(dd => new { dd.DepartmentId, dd.DayId });
entity.HasOne(dp => dp.Day)
.WithMany(p => p.DepartmentDays)
.HasForeignKey(d => d.DayId);
entity.HasOne(dp => dp.Department)
.WithMany(p => p.DepartmentDays)
.HasForeignKey(d => d.DepartmentId);
});
第一个问题:这种关系是可选的,我可以有几天不与部门联系吗?我需要这个,因为这与营业时间有关,并且希望有影响所有部门的通用日期,而不必与所有部门建立特定连接。但正如我一开始所说,我可能会以错误的方式看待这个问题。
第二个问题:如果第一个问题是真实有效的设置,我如何在 Linq 查询中获取那些未连接到部门的日子?
我目前拥有的是(编辑:将 allDays 从 Hashset 更改为 List。)
var allDays = await _context.Days.ToListAsync();
var allDepartmentDays = _context.DepartmentDays.Select(dd => dd.DayId).ToHashSet();
var genericDays = allDays.Where(d => !allDepartmentDays.Contains(d.Id));
还是在这里使用原始查询来提高性能更好?
SELECT Id
FROM Day
WHERE Id NOT IN (SELECT DayId FROM DepartmentDay)
编辑 2:包括整个数据模型
public class Department
{
public int Id { get; set; }
public int DepartmentNr { get; set; }
public string Service { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Address { get; set; }
public string Postal { get; set; }
public string City { get; set; }
public string Url { get; set; }
public string MapUrl { get; set; }
public DateTime Created { get; set; }
public string CreatedBy { get; set; }
public DateTime? Updated { get; set; }
public string UpdatedBy { get; set; }
public ICollection<DepartmentPeriod> DepartmentPeriods { get; set; }
public ICollection<DepartmentDay> DepartmentDays { get; set; }
}
public class DepartmentDay
{
public int DepartmentId { get; set; }
public int DayId { get; set; }
public Department Department { get; set; }
public Day.Models.Day Day { get; set; }
}
public class Day
{
public int Id { get; set; }
public int PeriodId { get; set; }
public string Service { get; set; }
public string City { get; set; }
public DateTime? Date { get; set; }
public DayOfWeek? DayOfWeek { get; set; }
public DateTime? OpenTime { get; set; }
public DateTime? CloseTime { get; set; }
public bool IsClosed { get; set; }
public string Description { get; set; }
public DateTime Created { get; set; }
public string CreatedBy { get; set; }
public DateTime? Updated { get; set; }
public string UpdatedBy { get; set; }
public ICollection<DepartmentDay> DepartmentDays { get; set; }
public virtual Period.Models.Period Period { get; set; }
}
modelBuilder.Entity<Day>(entity =>
{
entity.HasOne(d => d.Period)
.WithMany(p => p.Days)
.HasForeignKey(d => d.PeriodId);
});
还有一个关系没有包含在初始问题中,我的第一个问题的答案是Department 1-M DepartmentPeriod M-1 Period 1-1 Day。所以 Day table 中的某些日子与 DepartmentDay 无关,但仅与 Period 无关,对吗?
第一个问题:它是可选的吗?没有你的数据类型真的是一个棘手的问题,但假设你有正确的导航属性,你只需要指定导航属性,如果它们的键没有命名为 {DataType}Id,所以如果你这样命名它们就不是必需的,否则您必须指定要使用哪些外键字段以及哪些是键。如果您不指定关系,entity framework 将为您生成多对多关系的表。
第二个问题: 在性能方面,如果您能够编写一个好的查询,SQL 查询将始终优于您建议的查询,甚至
select a.id from [day] a left join departmentday b on a.id = b.dayid where b.dayid is null
即便如此,也可以表现得更好一些, 然而,就可测试性而言,sql 是一个问题,因为我们想要 运行 我们实体 dbcontext 的 InMemory 模型,然后你的 sql 通常至少不能执行。
所以问题是,如果您真的需要额外的性能,并且是否有可能编写一个 linq 查询,通过使其成为同一表达式的一部分而不是两个或更多表达式,从而有效地使 linq 引擎编写类似的查询.
在您的情况下,我可能会遗漏目前未提供的数据模型中的某些内容,但您似乎可以像这样获得您想要的内容:
_context.Days.Include(d => d.DepartmentDays).Where(!d.DepartmentDays.Any());
更新: 查看模型,似乎缺少一些模型工作,您正在寻找的投影可以按照建议的方式完成。
模型创建的更改/添加:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Department>()
.HasKey(k => k.Id);
modelBuilder.Entity<DepartmentDay>()
.HasKey(k => new { k.DayId, k.Department });
modelBuilder.Entity<Day>()
.HasOne(d => d.Period)
.WithMany(p => p.Days)
.HasPrincipalKey(k => k.PeriodId)
.HasForeignKey(d => d.Id);
//Notice your departmentid is not alone a foreign key in the relationship table, as departments can have one row per day
modelBuilder.Entity<DepartmentDay>()
.HasOne(a => a.Department)
.WithMany(b => b.DepartmentDays)
.HasPrincipalKey(p => p.Id)
.HasForeignKey(f => new { f.DepartmentId, f.DayId });
base.OnModelCreating(modelBuilder);
}
并且在上下文中我们可以使用以下方式进行此类查询:
public List<Day> GetDaysWithoutAnyDepartmentDays()
{
return Days
.Include(i => i.DepartmentDays)
.Where(x => !x.DepartmentDays.Any()
).ToList();
}