0

我可能以错误的方式看待这个问题,但我在 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 表中会有几天与 DepartmentDay 无关,而与 Period 无关,对吗?

4

1 回答 1

0

第一个问题:它是可选的吗?没有您的数据类型确实是一个棘手的问题,但是假设您正确设置了导航属性,如果它们的键未命名为 {DataType}Id,您只需要指定导航属性,因此如果您这样命名它们,则不需要,否则您必须指定要使用哪些外键字段以及哪些是键。如果您不指定关系,实体框架将为您生成多对多关系的表。

第二个问题:就性能而言,如果您能够编写一个好的查询,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();
}
于 2021-10-19T10:08:45.310 回答