【问题标题】:Core Data Query, most recent car per year?核心数据查询,每年最近的汽车?
【发布时间】:2017-11-16 03:03:28
【问题描述】:

在我的模型中,我有一个 Car 实体。

汽车 年 创建日期 名字

我想运行一个 fetch 来返回每年所有最近的汽车,其中 name 不是 nil(name 可以是 nil)。

因此,如果我有 3 辆 2000 年的汽车和 5 辆 2010 年的汽车,我想从获取请求中总共获得 2 辆汽车(最近的是 2000 年,最近的是 2010 年)。

我不确定如何编写正确的谓词来实现这一点。我查看了 returnDistinctResults 选项,但我不确定这是正确的路径,它还说它只适用于对我不起作用的 NSDictionaryResultType。

完成这项工作的正确查询/谓词是什么?

【问题讨论】:

    标签: ios swift core-data


    【解决方案1】:

    您最好使用算法简单地遍历每条记录。

    允许您的 Car 类,定义以下内容。

    struct C {
        var year: Int
        var created: Date
        var name: String?
    }
    
    var cars = [C(year: 2009, created: Date(), name: nil), C(year: 2009, created: Date(), name: "Green"), C(year: 2010, created: Date(), name: "Green"), C(year: 2010, created: Date(), name: "Orange"), C(year: 2010, created: Date(), name: "Orange")]
    
    var carsPerYear = [Int: [String: Int]]()
    
    for car in cars {
        if let name = car.name {
            var info: [String: Int]? = nil
            if carsPerYear.keys.contains(car.year) {
                info = carsPerYear[car.year]
            } else {
                info  = [String: Int]()
            }
            if !info!.keys.contains(name) {
                info![name] = 0
            }
            info![name] = info![name]! + 1
            carsPerYear[car.year] = info
        }
    }
    
    for year in carsPerYear.keys {
        let info = carsPerYear[year]!
        let sorted = info.keys.sorted{ info[$0]! > info[$1]! }
        print(year, sorted.first!)
    }
    

    给出输出

    2009 Green 
    2010 Orange
    

    有时SQL或CoreData不能轻易解决问题,最好只写排序算法。

    【讨论】:

      【解决方案2】:

      您可以实现这一点,假设您将一个年份数组传递给一个算法,并期望以字典的形式得到一个结果,每一年您作为一个对象的键传入,该对象对应于最那年最近的车。

      即:

      let years : [Int] = [2000, 2005]
      
      
      //The ideal method:
      
      func mostRecentFor<T>(years: [Int]) -> [String:T]
      

      假设您只使用少量搜索年份,并且您的数据库中有少量汽车,您不必担心线程问题。否则,对于这种方法,您必须使用并发或专用线程进行提取以避免阻塞主线程。出于测试目的,您不需要这样做。

      要做到这一点,您可以使用以下方法。

      首先,应该像其他答案所建议的那样在年份上使用数字谓词。 为此,您将使用 NSPredicate 的日期格式:

      NSPredicate(format: "date == %@", year)
      

      因此,您的模型应该将年份作为参数,将实际的 nsdate 作为另一个参数。然后,您将使用设置为 1 的 fecthLimit 参数,并将 sortDescriptor 应用于 nsDate 键参数。后两者的组合将确保只返回给定年份的最年轻或最旧的值。

      func mostRecentFor(years: [Int]) -> [String:Car] {
              let result : [String:Car] = [:]
              for year in years {
                 let request: NSFetchRequest<CarModel> = CarModel.fetchRequest()
                 request.predicate = NSPredicate(format: "date == %@ AND name != nil", year)
                 request.fetchLimit = 1
                 let NSDateDescriptor: let sectionSortDescriptor = NSSortDescriptor(key: "nsDate", ascending: true)
                 let descriptors = [NSDateDescriptor]
                 fetchRequest.sortDescriptors = descriptors
                 do {
                      let fetched = try self.managedObjectContext.fetch(request) as 
                      [CarModel]
                      guard !fetched.isEmpty, fetched.count == 1 else {
                          print("No Car For year: \(year)")
                          return
                      }
                      result["\(year)"] = new[0].resultingCarStruct //custom parameter here.. see bellow
                  } catch let err {
                      print("Error for Year: \(year), \(err.localizedDescription)")
                  }
              }
              return result
      }
      

      我们在这里使用升序设置为true,因为我们希望第一个值,即由于fetchLimit值为1而实际返回的值,是该年份最早的汽车,或者是最小的汽车nsDate 键的时间戳。

      这应该为您提供一个用于小型数据存储和测试的简单获取查询。此外,创建一个方法或参数来将 CarModel 解释为其对应的 Car 结构体可以更简单地从 CD 转到内存对象。

      所以你会像这样搜索你的汽车:

      let years = [1985, 1999, 2005]
      let cars = mostRecentFor(years: years)
      
      // cars = ["1985": Car<year: 1985, name: "Chevrolet", nsDate: "April 5th 1985">, "1999" : Car<year: 1999, name: "Toyota Corolla", nsDate: "February 5th 1999">]
      // This examples suggests that no cars were found for 2005
      

      【讨论】:

      • 我明白你的意思,这有三个问题: 1. 这种方法需要大量的磁盘,非常非常慢。 2.这个问题不是要求通过一系列年份,我只是想要每年最近的汽车 3.这个答案没有考虑名称!= nil 条件。谢谢。
      • 1:我指定此方法适用于测试/小型数据库,并且您需要将其调整为并发包装器以获取更多信息。 2:“每年”可以表示从一组年份到两个给定年份之间的每一年的任何内容,这至少会导致一个年份数组(或在这种情况下为整数)。 3:确实我忘记了名字,检查 nil 是通过在谓词字符串中添加一个 AND 运算符来完成的,然后在字符串中或使用参数符号添加该避免的值。生病更新
      • 这没有提供问题所要求的答案。对不起。
      • 您的问题是询问查询中指定的每年最早的汽车,其名称没有零?
      • “核心数据查询”,而不是“核心数据查询”。一个查询得到我想要的。您提供的内容在我可能传入的每一年都会进入磁盘。另外,正如我上面所说,我没有指定我想在几年内传递。那是您在此处添加的内容...所以,再次抱歉,但您的回答并未解决问题。谢谢
      猜你喜欢
      • 2021-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-29
      • 2012-06-15
      • 1970-01-01
      • 1970-01-01
      • 2020-12-01
      相关资源
      最近更新 更多