Есть приложение с Core Data - в нем две сущности, допустим “Ученики” и “Предметы”. В первом перечислены параметры Имя, Возраст, Пол и т.д… Во втором перечислены Название предмета, описание предмета, план обучения и т.д… Мне надо связать Учеников с Предметами, при этом чтобы еще оценка сохранялась, получается типа “табеля оценок”, например:
"ученик Иванов:
1)математика - 5
2)история - 4
3)география - 5"
Тут наверняка надо использовать Dictionary. Но не могу дотукаться - где и как оценки прописать?
Я не могу найти данных по CoreData где бы обьяснялась похожая схема.
Как работать с Dictionary в CoreData?
Сохранения в CoreData
Сделайте три сущности ученики/оценки/предметы и свяжите учеников с оценками а оценки с предметами.
Спасибо за ответ
Я попробовал, но не понял как тогда будет работать связь “Ученик - Предмет” ?
У ученика будут несколько оценок (возможно одинаковых), без "Предметов"
У “Предмета” будут несколько оценок (от разных учеников), но без прямой привязки к Ученикам
Ученик -> Оценка -> Предмет, у ученика есть оценки у оценок предметы. Связи в CoreData двухсторонние (по крайней мере должны быть) по этому Предмет -> Оценка -> Ученик, то же будет работать. Можете сделать ещё одну связь Ученик -> Предмет (на случай если ученик не получил оценку по предмету) и в цикле предметов фильтровать оценки по предмету.
Спасибо за ответ, но честно говоря не понятно как это практически в коде сделать. В интернете нахожу информацию про Core Data, но про связи сущности везде показывают только в виде графики, а не в программном коде. Вот ниже код из моего приложения. Есть сущность Heroes (это Ученики), куда заполняются его данные при нажатии кнопки Save. Я создал сущности Badges (это типа Предметы) и Status (Оценки). В Badges есть name. В Status есть badgeStatus. Графически я сделал между ними стрелочки и всё - дальше непонятно как это использовать. В примерах, которые я нагуглил в основном рассматривают связь только между 2 сущностями, в моем же случае это 3 сущности
@IBAction func saveButtonPressed(sender: AnyObject) {
if nameHeroTextField.text == "" || ageHeroTextField.text == "" /*|| genderHeroTextField.text == ""*/ {
print("не все поля заполнены")
}else{
if let context = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer.viewContext{
let fetchRequest: NSFetchRequest<Heroes>=Heroes.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "name != nil")
var records = 0
do {
let count = try context.count(for: fetchRequest)
records = count
} catch {
print (error.localizedDescription)
}
let heroes = Heroes(context: context)
heroes.name = nameHeroTextField.text
heroes.age = ageHeroTextField.text
heroes.numberHero = Int32(records+1)
do {
try context.save()
print("Все сохранилось!")
} catch let error as NSError {
print ("Не удалось сохранить данные\(error),\(error.userInfo)")
}
}
performSegue(withIdentifier: "newHeroClose", sender: self)
}
}
Большое спасибо, так подробно расписали, что понадобится время чтобы переварить, но кое-какие выводы сделал
- Придется переделать у себя модель, во-первых у вас больше связей, а во вторых у меня все Entity уже в модели были объявлены как класс. Судя по вашему примеру и ответу на прошлый вопрос - класс надо объявить через создания отдельного файла, чтобы внутри можно было создать сабкласс
- К каждому герою надо присвоить все Badge (их около 50 штук). в смысле HeroA = [badge01, badge02,badge03…badge48, badge49, badge50]
- Потом уже можно будет через status.badge и status.hero присвоить каждому герою статус за каждый предмет.
Я только не пойму почему вы в примере привязываете оценку к предмету и ученику, а не наоборот. Получается вот оценка 3, её присваиваем к “Математике” и к ученику Иванову, это немного сбивает с толку, хотя наверное это уже не так важно. В моем приложении будет выбор ученика, потом вылезает список предметов, потом заходим в любой предмет и там через кнопку ставим определенный status. В этот момент думаю нужно определить только какой предмет выбран и какой ученик и потом через status.badge и status.hero сохранить соответствующий статус (оценку)
еще вопрос - у меня у сущности Heroes на самом деле 5 аттрибутов
нужно ли все эти аттрибуты указать через @NSManaged ? или там нужно указывать только ключевые аттрибуты, которые нужны для связи с другими сущностями
В вашем примере последние 2 строки, где используете filter и map - если честно тут у меня мозг просто ломается
Понимаю, что написано чтобы коротко было, но сложно для понимания как определять оценку предмета
Это можно как-то по-другому написать?
hero.badges?.forEach { badge in
let values = hero.statuses?.filter { $0.badge == badge }.map { $0.value } ?? []
print(" (badge.name!) (values)")
}
let result = try! context.fetch(request)
for hero in result {
print(hero.name!)
for badge in hero.badges ?? [] {
var values = [Int]()
for status in hero.statuses ?? [] where status.badge == badge {
values.append(status.value)
}
print(" \(badge.name!) \(values)")
}
}
Извиняюсь что реально туплю, хоть убейте, но так и не получается у меня. С помощью ваших подсказок я сделал такую же модель, привязал к ученику все предметы, теперь мне надо поставить “оценки” (status). Я решил изначально всем поставить status = 0, то есть никакой предмет еще не проверялся. Сделал в отдельной функции. Тут берется конкретный выбранный ученик (selectedHero), его указываю в status.hero, потом поочередно также в статус загружаю каждый badge и заодно присваиваю значение = 0, вот мой код
func setHeroStatus() {
let status = Status(context: context!)
status.hero = selectedHero
for badge in selectedHero.badgeHero! { // перебираем все значки
status.badge = b //привязываем значки к статусу
status.value = 0 // у всех значков должно быть статус = 0
}}
try! context?.save()
Потом смотрю что сохранилось, программа почему-то выборочно сохраняет в некоторые Badge, а в некоторые ничего не сохраняет, вот что выгружает (Romashka - это имя ученика). Что я делаю не так?
Romashka
BADGE 1 []
BADGE 5 []
BADGE 4 []
BADGE 3 [0]
BADGE 2 [0]
Нужно делать новый Status для каждого Badge:
func setHeroStatus() {
for badge in selectedHero.badgeHero! {
let status = Status(context: context!)
status.hero = selectedHero
status.badge = b
status.value = 0
}
}
Получилось! Еще раз спасибо -)
Только 2 строчки передвинул внутрь цикла и все заработало
Хотя не очень понял почему это повлияло.
Я понимал, что объявляю let status = Status(context: context!),
потом указываю конкретного героя status.hero = selectedHero
а значит далее в цикле все badge и statusValue присваиваются к этому герою.
Догадываюсь, что без эти двух команд в цикле программа наверное присваивала только первому значению.
Еще мне непонятно как расшифровать это
for badge in hero.badges ?? []
точнее последние символы = ?? []
Это ведь используется в основном при присваении значений