我正在尝试保存一个具有 IsarLink 的模型,每个模型也都有一个 IsarLink。 保存 IsarLinks(设置为 WorkoutSets)可以工作,但内部的 IsarLink(练习作为练习)不会保留。以下是保存模型以及模型本身的方法。
///contained in a separate class
static saveWorkout(Workout workout) async {
await isar!.writeTxn(() async {
List<Exercise> exercises = workout.workoutExercises.toList();
await isar!.workouts.put(workout);
for (Exercise exercise in exercises) {
await isar!.exercises.put(exercise);
workout.exercises.add(exercise);
}
for (Exercise exercise in exercises) {
List<WorkoutSet> sets = exercise.sets.toList();
for (WorkoutSet set in sets) {
await isar!.workoutSets.put(set); // Save set with link
set.exercise.value = exercise; // Link set to exercise
await set.exercise.save();
workout.sets.add(set); // Prepare to link set to workout
}
}
await workout.sets.save();
await workout.exercises.save();
});
}
@Collection(inheritance: false)
class Workout extends Equatable {
final String id;
Id get isarId => Crypto.fastHash(id);
IsarLink<WorkoutTemplate> template = IsarLink<WorkoutTemplate>();
@override
@ignore
List<Object?> get props => [
id,
performedOn,
durationSeconds,
sets,
workoutExercises,
template,
];
@Index()
DateTime performedOn;
int durationSeconds = 0;
Workout({
required this.id,
required this.performedOn,
List<Exercise>? workoutExercises, // Allow passing exercises to constructor
}) : workoutExercises =
workoutExercises ?? List<Exercise>.empty(growable: true);
final sets = IsarLinks<WorkoutSet>();
///used only for finding workout by exercises used in the workout e.g. for workout history
final exercises = IsarLinks<Exercise>();
@ignore
final List<Exercise> workoutExercises;
@ignore
get totalWeightLifted {
return sets.fold<double>(
0, (previousValue, element) => previousValue + (element.weight ?? 0));
}
void prepareForSaving() {
template.value?.exercises = workoutExercises;
}
Workout clone() {
var templateClone = IsarLink<WorkoutTemplate>();
if (template.value != null) {
templateClone.value = template.value; // Adjust according to your needs
}
List<Exercise> exercisesClone =
workoutExercises.map((e) => e.clone()).toList();
return Workout(
id: id,
performedOn: DateTime.fromMillisecondsSinceEpoch(
performedOn.millisecondsSinceEpoch),
workoutExercises: exercisesClone,
)
..durationSeconds = durationSeconds
..template = templateClone;
}
addExercises(List<Exercise> exercises) async {
for (var exercise in exercises) {
var newExercise = exercise.clone();
newExercise.sets.add(WorkoutSet(performedAs: 0, exercise: exercise));
workoutExercises.add(newExercise);
}
}
addSet(int exerciseIndex) async {
workoutExercises[exerciseIndex].sets.add(WorkoutSet(
performedAs: workoutExercises[exerciseIndex].sets.length,
exercise: workoutExercises[exerciseIndex]));
}
removeSet(int exerciseIndex, int setIndex) {
workoutExercises[exerciseIndex].sets.removeAt(setIndex);
for (final (index, set) in workoutExercises[exerciseIndex].sets.indexed) {
set.performedAs = index;
}
}
Exercise? getExercise(int index) {
var id = template.value?.exerciseIds.elementAtOrNull(index);
if (id == null) {
return null;
}
return Database.isar!.exercises
.where()
.idEqualTo(int.parse(id))
.findFirstSync();
}
factory Workout.empty() {
return Workout(
id: Uuid().v4(),
performedOn: DateTime.now(),
);
}
}
@Collection(inheritance: false)
class WorkoutSet extends Equatable {
WorkoutSet({
this.performedOn,
this.weight,
this.reps,
this.type = SetType.work,
required this.performedAs,
this.completed = false,
this.note,
this.isChecked = false,
this.rpe,
this.restTimer,
this.autoRestTimer,
Exercise? exercise,
}) : uuid = Uuid().v4() {
this.exercise.value = exercise;
}
@override
@ignore
List<Object?> get props => [
performedOn,
weight,
reps,
type,
performedAs,
completed,
note,
isChecked,
];
WorkoutSet clone() {
return WorkoutSet(
performedOn:
performedOn, // DateTime is immutable in Dart, so direct assignment is okay
weight: weight,
reps: reps,
type: type, // Enums are immutable
performedAs: performedAs,
// Add the rest of the properties following the same pattern
rpe: rpe,
restTimer: restTimer,
autoRestTimer: autoRestTimer,
completed: completed,
note: note,
isChecked: isChecked,
exercise: exercise.value,
)
..id = id
// ..exercise = exercise
..uuid = uuid;
}
// LINK PR
Id id = Isar.autoIncrement;
String uuid;
IsarLink<Exercise> exercise = IsarLink<Exercise>();
@enumerated
SetType type;
int? weight;
int? reps;
int? rpe; // e.g. 8.5 = 85
int? restTimer; // in seconds e.g. 300 = 5 Minutes
int? autoRestTimer;
bool completed = false;
String? note;
bool isChecked = false;
DateTime? performedOn;
int performedAs; // represents, when - during a number of sets of the same exercise - this set was performed
}
enum SetType {
work,
warmup,
dropSet,
failure,
}
extension Utils on SetType {
Color color(BuildContext context) {
switch (this) {
case SetType.work:
return Theme.of(context).colorScheme.secondaryContainer;
case SetType.warmup:
return Colors.yellow.shade200;
case SetType.dropSet:
return Colors.purple.shade200;
case SetType.failure:
return Colors.redAccent.shade100;
default:
return Theme.of(context).colorScheme.secondaryContainer;
}
}
Color textColor(BuildContext context) {
switch (this) {
case SetType.work:
return Theme.of(context).colorScheme.onSurface;
case SetType.warmup:
return Colors.yellow.shade800;
case SetType.dropSet:
return Colors.purple.shade800;
case SetType.failure:
return Colors.redAccent.shade700;
default:
return Theme.of(context).colorScheme.secondaryContainer;
}
}
}
extension Formatting on SetType {
String format() {
return name.toUpperCase();
}
}
enum BarType {
olympic,
short,
ez,
hex,
none,
}
enum UnitType {
metric,
imperial,
}
我尝试在保存后再次进行锻炼,但这不会改变任何东西。
尝试了很多变体,但都不起作用。最终只是简单地存储所需练习的 ID 并为其实现 getter,而不是使用链接。