Buat kolom dalam permintaan pengambilan berdasarkan ekspresi

RINGKASAN

Saya ingin dapat membuat nilai baru berdasarkan ekspresi dalam pengambilanRequest dari entitas Data Inti.

Memiliki entitas dengan atribut ini (versi singkat)

  Name              Attributes
[Course] -> {licenseStart, name, id}

Saya ingin membuat FetchResquest pada entitas itu dan mengambil kamus dengan semua atribut ditambah satu basis lagi pada ekspresi ini:

licenseStart.doubleValue / 1000 < NSDate().timeIntervalSince1970 ? "Actually" : "Cooming Soon"

Jadi hasilnya adalah:

[ "licenseStart":1,"id":3, "name":"A", "status":0, ...
  "licenseStart":2,"id":4, "name":"B", "status":0, ...
  "licenseStart":3,"id":6, "name":"B", "status":0, ...
  "licenseStart":4,"id":2, "name":"C", "status":0, ...
  "licenseStart":5,"id":1, "name":"D", "status":1, ...
  "licenseStart":6,"id":7, "name":"E", "status":1, ...
]

POSTING

Saya ingin mengajukan pertanyaan untuk masalah yang saya hadapi sejak beberapa hari ini.. setiap pendekatan yang saya coba berakhir dengan solusi yang lebih kompleks.

Izinkan saya menjelaskan kepada Anda situasinya:

Saya memiliki Model CoreData dengan entitas yang memiliki atribut berbeda-beda, salah satunya adalah lisensi mulai ini adalah nomor stempel waktu unix yang digunakan untuk menentukan kapan suatu kursus akan dimulai.

Jadi, ketika saya ingin mengisi data untuk membuat UITableView dengan kursus, saya mengambil semua informasi ini dari database tanpa masalah sama sekali, saya menggunakan atribut licenseStart ini untuk menghitung bagian berdasarkan rumus , ini adalah kode untuk UITableView

UITableViewController

let entity = NSEntityDescription.entityForName("Course", inManagedObjectContext: managedObjectContext!)
        let req = NSFetchRequest()
        let predicate = sectionProtocol?.FRCPredicate
        let sort = [NSSortDescriptor(key: "licenseStart", ascending: true), NSSortDescriptor(key: "name", ascending: true), NSSortDescriptor(key: "courseId", ascending: true)]
        req.entity = entity
        req.sortDescriptors = sort
        req.predicate = predicate
        /* NSFetchedResultsController initialization
        a 'nil' 'sectionNameKeyPath' generates a single section */
        var aFetchedResultsController = NSFetchedResultsController(fetchRequest: req, managedObjectContext: managedObjectContext!, sectionNameKeyPath:"dateStatus", cacheName: nil)

Setelah ini hasil saya (contoh kecil) seperti ini

[ "licenseStart":1,"id":3, "name":"A",...
  "licenseStart":2,"id":4, "name":"B",...
  "licenseStart":3,"id":6, "name":"B",...
  "licenseStart":4,"id":2, "name":"C",...
  "licenseStart":5,"id":1, "name":"D",...
  "licenseStart":6,"id":7, "name":"E",
]

Apa yang saya miliki di UITableView adalah:

[Actually] 
  [A]
  [B]
  [B]
  [C]
[Cooming Soon]
  [D]
  [E]

Jadi, yang saya lakukan sekarang adalah menggunakan licenseStart untuk membuat dua bagian, caranya?, mudah, cukup gunakan atribut model saya yang bernama dateStatus dan buat dua kemungkinan hasil menggunakan lisensi dimulai sebagai berikut:

Kelas Model

var dateStatus : Int {
        get {
            return licenseStart.doubleValue / 1000 < NSDate().timeIntervalSince1970 ? "Actually" : "Cooming Soon"
        }
 }

Jadi sekali lagi di UITableView saya menggunakan metode delegasi dataSource untuk mengisi baris dan bagian.

MASALAH

Sampai saat ini semuanya bekerja dengan sempurna. Tapi sekarang saya ingin menambahkan opsi pengurutan yang memungkinkan pengguna mengurutkan hasil secara menaik atau menurun, masalahnya adalah ketika saya mengurutkan, yaitu menaik menggunakan opsi pengurutan yang berbeda:

let entity = NSEntityDescription.entityForName("Course", inManagedObjectContext: managedObjectContext!)
        let req = NSFetchRequest()
        let predicate = sectionProtocol?.FRCPredicate
        let sort = [NSSortDescriptor(key: "licenseStart", ascending: true), NSSortDescriptor(key: "name", ascending: false), NSSortDescriptor(key: "courseId", ascending: false)]
        req.entity = entity
        req.sortDescriptors = sort
        req.predicate = predicate
        /* NSFetchedResultsController initialization
        a 'nil' 'sectionNameKeyPath' generates a single section */
        var aFetchedResultsController = NSFetchedResultsController(fetchRequest: req, managedObjectContext: managedObjectContext!, sectionNameKeyPath:"dateStatus", cacheName: nil)

Karena cara saya membuat bagian berdasarkan LicenseStart, hasil pengambilan ini akan sama persis seperti sebelumnya:

[ "licenseStart":1,"id":3, "name":"A",...
  "licenseStart":2,"id":4, "name":"B",...
  "licenseStart":3,"id":6, "name":"B",...
  "licenseStart":4,"id":2, "name":"C",...
  "licenseStart":5,"id":1, "name":"D",...
  "licenseStart":6,"id":7, "name":"E",
]

Apa yang saya miliki di UITableView adalah:

[Actually] 
  [A]
  [B]
  [B]
  [C]
[Coming Soon]
  [D]
  [E]

Mengapa? karena lisensiStart semuanya berbeda dan menggunakan elemen pertama ini di NSSortDescriptors untuk mengambil data.. ini bukan perilaku yang saya inginkan, yang saya inginkan adalah memiliki bagian-bagian dalam urutan yang persis sama seperti sebelumnya tetapi elemen-elemen di dalamnya diatur berbeda

i.e:

[Actually] 
  [C]
  [B]
  [B]
  [A]
[Coming Soon]
  [E]
  [D]

SOLUSI YANG MUNGKIN

Apa yang saya pikirkan adalah membuat kolom baru selama permintaan pengambilan, jika saya dapat mengevaluasi ekspresi ini licenseStart.doubleValue / 1000 < NSDate().timeIntervalSince1970 ? 0 : 1 pada saat mengambil data, saya akan memiliki kolom baru dengan 0 dan 1 seperti ini pada hasilnya:

[ "licenseStart":1,"id":3, "name":"A", "status":0, ...
  "licenseStart":2,"id":4, "name":"B", "status":0, ...
  "licenseStart":3,"id":6, "name":"B", "status":0, ...
  "licenseStart":4,"id":2, "name":"C", "status":0, ...
  "licenseStart":5,"id":1, "name":"D", "status":1, ...
  "licenseStart":6,"id":7, "name":"E", "status":1, ...
]

Dan sekarang saya dapat menggunakan status ini untuk membuat bagian di NSSortDescriptors [NSSortDescriptor(key: "status", ascending: true),NSSortDescriptor(key: "licenseStart", ascending: true), NSSortDescriptor(key: "name", ascending: true), NSSortDescriptor(key: "courseId", ascending: true)] untuk naik dan [NSSortDescriptor(key: "status", ascending: true),NSSortDescriptor(key: "licenseStart", ascending: false), NSSortDescriptor(key: "name", ascending: false), NSSortDescriptor(key: "courseId", ascending: false)] untuk turun.

Ini akan memberi saya perilaku yang saya inginkan.. tetapi saya belum dapat menemukan cara yang baik dan bersih untuk melakukan ini. Saya sudah mencoba melakukan ini menggunakan NSExpressions tetapi saya tidak dapat menggunakan kurang dari dengan pengambilan CoreData..

Selain itu, solusi yang mungkin adalah membuat kolom baru ini di model data saya dan menghasilkan nilai ini saat menyimpan data, tetapi ini bukan pendekatan yang valid karena nilai lisensiStart ini harus dibandingkan dengan stempel waktu saat ini setiap kali pengguna mengisi tabel ini.

Saya bertanya apakah seseorang memiliki ide singkat atau solusi cerdas untuk masalah ini.

Di MySQL atau SQLite mudah untuk membuat kolom baru berdasarkan nilai atau ekspresi tertentu tetapi di coredata saya seorang pemula jadi saya tidak melihat cara yang jelas untuk melakukan ini.

Terima kasih banyak.


person neteot    schedule 16.03.2017    source sumber
comment
Itu pertanyaan yang sangat panjang. Bisakah Anda meletakkan ringkasan di suatu tempat (mungkin di atas) yang menunjukkan hasil akhir yang ingin Anda capai, dan apa yang sebenarnya Anda dapatkan. Ini tampak seperti aliran kesadaran - berguna untuk menenangkan pikiran Anda, tetapi sulit untuk melihat apa masalah sebenarnya.   -  person Ashley Mills    schedule 16.03.2017
comment
Menambahkan ringkasan, terima kasih atas masukannya @AshleyMills :)   -  person neteot    schedule 16.03.2017


Jawaban (2)


Saya mengalami situasi di mana saya ingin memisahkan beberapa elemen agar berada di urutan teratas daftar bukan berdasarkan atribut data inti. Saya melakukan pengambilan dengan FetchedResultsController dan kemudian melakukan satu kali proses untuk memasukkan elemen ke dalam dua array (O(n)) dengan menjaga agar tetap diurutkan berdasarkan jenis aslinya. Ketika elemen berubah, saya harus menemukannya di array saya untuk mengubahnya, tetapi itu tidak sesulit yang saya harapkan.

Solusi yang lebih mudah adalah dengan menggunakan dua FetchedResultsController.

person Jon Rose    schedule 16.03.2017

Cobalah untuk tidak menganggap CoreData sebagai database sql relasional biasa tempat Anda dapat membuat kolom dalam kueri Anda.

Sepertinya yang Anda perlukan hanyalah menambahkan atribut lain status ke entitas Anda. Setiap kali Anda memperbarui licenseStart, cukup setel nilai status.

Jika Anda menggunakan codegen juga

extension Course {
    func updateLicenseStart(date: Date) {
        licenseStart = date
        status = licenseStart.doubleValue / 1000 < Date().timeIntervalSince1970 ? 0 : 1
    } 
}

atau ganti nama atribut yang mendasarinya…

extension Course {
    var licenseStart {
        set {
            _licenseStart = newValue 
            status = licenseStart.doubleValue / 1000 < Date().timeIntervalSince1970 ? 0 : 1
        }
        get { return _licenseStart }
    } 
}

Jika Anda mempertahankan kelas model Anda sendiri, Anda tidak dapat menambahkan pengamat properti ke @NSManaged var, tetapi Anda dapat menghapus @NSManaged dan mengganti set dan get

public var licenseStart: Date {
    set {
        willChangeValueForKey("licenseStart")
        setPrimitiveValue(newValue, forKey: "licenseStart")
        status = licenseStart.doubleValue / 1000 < Date().timeIntervalSince1970 ? 0 : 1
        didChangeValueForKey("licenseStart")
    }
    get {
        willAccessValueForKey("licenseStart")
        let date = primitiveValueForKey("licenseStart") as? Date
        didAccessValueForKey("licenseStart")
        return date
    }
}
person Ashley Mills    schedule 16.03.2017
comment
Ya, saya memikirkan solusi itu untuk pertama kalinya. Tetapi masalahnya adalah ketika Anda mengambil data dari server dan menyimpannya di Data Inti, statusnya akan didasarkan pada momen itu, tetapi yang saya perlukan adalah memiliki status berdasarkan stempel waktu saat ini setiap kali pengguna mengisi tampilan tabel dan Saya meneruskan FetchResultsController.fetchedObjects ke metode delegasi tampilan tabel. - person neteot; 16.03.2017
comment
Ah, sepertinya aku mengerti. Berapa banyak baris yang sedang kita bicarakan? Seberapa akurat waktu yang dibutuhkan? Bisakah Anda melakukan pembaruan batch pada permulaan aplikasi/latar depan/sebelum tabel diisi dan menetapkan status pada setiap baris? - person Ashley Mills; 16.03.2017
comment
Bukankah ini masalah kuantitas tetapi aplikasi ini memiliki semua fungsi lengkap offline yang memungkinkan pengguna menyelesaikan kursus secara offline (mengunduh semua konten kursus) dan kemudian ketika koneksi aktif kembali, ia meluncurkan fungsi pembaruan. Jadi mungkin berhari-hari akan ada bagian yang tidak konsisten (mungkin akan tertulis segera hadir padahal saat ini) :S. Saya dapat membuat NSExpression dengan propertiToFetch dan membuat nilai baru (tetapi saya tidak dapat menggunakan fungsi kompleks seperti licenseStart.doubleValue / 1000 < NSDate().timeIntervalSince1970 ? 0 : 1 di atas - person neteot; 16.03.2017