【问题标题】:How to use Linq in C# to select a specific string from multiple nested columns?如何在 C# 中使用 Linq 从多个嵌套列中选择特定字符串?
【发布时间】:2020-04-03 01:13:19
【问题描述】:

我有一个小问题。我有以下表格及其关系:

Building
  Batteries
    Columns
      Elevators

一座建筑可以有很多电池,电池可以有很多柱子,柱子可以有很多电梯。

一个电池有一个建筑物,一个柱子有一个电池,电梯有一个柱子。

如果我这样做var myintervention = _context.buildings.Where(b => b.batteries.Any(ba => ba.status == "Intervention")).ToList();,它将在我的查询中完美地返回具有干预状态的电池的建筑物列表(状态是一列)。

问题是我不能做像_context.buildings.Where(c => c.columns.Any...) 这样的事情,因为建筑模型无法访问列类,但电池可以......电梯也是如此,建筑物无法访问电梯, 列。

这是我定义模型构建器的方式:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Battery>()
            .HasOne(p => p.buildings)
            .WithMany(b => b.batteries)
            .HasForeignKey(p => p.building_id);

        modelBuilder.Entity<Column>()
            .HasOne(p => p.batteries)
            .WithMany(b => b.columns)
            .HasForeignKey(p => p.battery_id);

        modelBuilder.Entity<Elevator>()
            .HasOne(p => p.columns)
            .WithMany(b => b.elevators)
            .HasForeignKey(p => p.column_id);
    }

这是我的关系在我的模型中的样子:

building.cs
  public List<Battery> batteries { get; set; }

battery.cs
  public long building_id { get; set; }
  public Building buildings { get; set; }
  public List<Column> columns { get; set; }

column.cs
  public long battery_id { get; set; }
  public Battery batteries { get; set; }
  public List<Elevator> elevators { get; set; }

elevator.cs
  public long column_id { get; set; }
  public Column columns { get; set; }

tl;博士;我想做一个 linq 查询来列出所有有电池、柱子或电梯的建筑物,它们的状态列是“干预”。

更新:显然这在某种程度上可行,但效率不高:

var myintervention = _context.buildings.Where(a => a.batteries.SelectMany(b => b.columns.SelectMany(c => c.elevators)).Any(c => c.status == "Intervention")).ToList();

好像不准确?有时有电池在干预,与这些电池关联的建筑物不会出现在建筑物列表中。电梯或柱子也是如此。我有点迷路了!

更新 2:这是我的要求:

[HttpGet("intervention")]
        public List<Building> Getintervention(string status)
        {
            var myintervention = _context.buildings.Where(c => c.batteries.SelectMany(z => z.columns).Any(z => z.status == "Intervention")).ToList();
            return myintervention;
        }

【问题讨论】:

  • c.batteries.SelectMany(z =&gt; z.columns).Any 可以吗?
  • 嗯,像var myintervention = _context.buildings.Where(c =&gt; c.batteries.SelectMany(z =&gt; z.columns).Any(z =&gt; z.status == "Intervention")).ToList(); 这样的东西确实可以显示建筑物列表,但我确定它的链接是什么?当我检查所选建筑物的 id 时,它不对应于具有干预状态的列或电池 :(
  • 有没有机会让多个属性名称与单数/集合一致?例如battery.cs(应该称为Battery.cs)应该有public Building Building - 它是令人困惑的 *!%# 有一个具有复数名称的属性(所以你假设它是一个集合)但它是一个对象(所以你希望能够说 buildings.Where 但你只能在集合上这样做。c# 中的属性名称以大写字母开头
  • @JeunePadawan 与其编辑掉你的问题,如果你觉得它不再有用,请删除它。

标签: c# mysql entity-framework linq


【解决方案1】:

首先,请修复模型,使集合名称为复数,对象名称为单,否则您的代码会变得很混乱:

building.cs
  public List<Battery> Batteries { get; set; }

battery.cs
  public long BuildingId { get; set; }
  public Building Building { get; set; }
  public List<Column> Columns { get; set; }

column.cs
  public long BatteryId { get; set; }
  public Battery Battery { get; set; }
  public List<Elevator> Elevators { get; set; }

elevator.cs
  public long ColumnId { get; set; }
  public Column Columns { get; set; }

现在让我们为模型添加更多属性,以便它可以告诉我们干预措施:

building.cs
  public List<Battery> Batteries { get; set; }

  [NotMapped]
  public bool IsInIntervention => this.Status == "Intervention" || Batteries.Any(b => b.IsInIntervention);

battery.cs
  public long BuildingId { get; set; }
  public Building Building { get; set; }
  public List<Column> Columns { get; set; }

  [NotMapped]
  public bool IsInIntervention => this.Status == "Intervention" || Columns.Any(c => c.IsInIntervention);


column.cs
  public long BatteryId { get; set; }
  public Battery Battery { get; set; }
  public List<Elevator> Elevators { get; set; }

  [NotMapped]
  public bool IsInIntervention => this.Status == "Intervention" || Elevators.Any(e => e.IsInIntervention);


elevator.cs
  public long ColumnId { get; set; }
  public Column Column { get; set; }

  [NotMapped]
  public bool IsInIntervention => this.Status == "Intervention";


现在你可以问一栋建筑是否为 IsInIntervention,如果它是或它拥有的任何东西,它会说是

注意:如果模型还没有加载实体,那么您可能需要使用这样的技巧:EF Core linq and conditional include and theninclude problem 有条件地加载它们

【讨论】:

  • 哇,非常感谢这一切...是的,我现在正在更改所有内容,但我左右都犯了错误,考虑到已经过了凌晨 2 点,我太累了。不过我很好奇,你会如何查询 IsInIntervention 呢?我用我提出的要求更新了主帖。如果这没有意义,我很抱歉,我明天早上会读回所有内容。非常感谢您的帮助,我衷心感谢。
  • 嗯。看起来我不能在模型中执行布尔运算,我收到此错误:System.Linq.dll 中发生“System.ArgumentNullException”类型的异常,但未在用户代码中处理:“值不能为空。” .尝试修复它,但我还不够好,哈哈
  • 我认为这将是因为数据未加载所以例如 build.Batteries 为空;你看到我粘贴的关于使用 include/theninclude 查询的链接了吗?我们在谈论多少建筑物/电池/立柱/电梯?
  • 现在可以使用了!编辑问题以显示答案!
  • 可能不应该如此彻底地编辑问题以使答案变得毫无意义 - 将您的编辑作为答案发布(并且您可以接受它)并标记任何其他有用的答案,并点赞。要访问问题的编辑修订版(复制您当前的编辑,将问题恢复为先前的编辑并将复制的文本作为答案发布)点击问题上的“已编辑 x 分钟前”链接
【解决方案2】:
var vara = _context.maintable.Where(a => a.tablerelatedtomain.SelectMany(b => b.tablerelatedtoprevious).SelectMany(c => c.tablerelatedtoprevious).Any(c => c.status == "mystring")).ToList();
var varb = _context.maintable.Where(a => a.tablerelatedtomain.SelectMany(b => b.tablerelatedtoprevious).Any(b => b.status == "mystring")).ToList();
var varc = _context.maintable.Where(a => a.tablerelatedtomain.Any(a => a.status == "mystring")).ToList();
var result = vara.Union(varb).Union(varc).OrderBy(z => z.id).ToList();

return result;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-15
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 2017-06-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多