我有这个模型。运动员有多项训练和多项训练计划。锻炼可以在许多培训计划中进行。锻炼可以在一天内进行多次,这就是为什么我需要M:M关系中的额外字段DateToPerform。我怎么能完成它,这是我的模型:
public class Athlete
{
public int Id {get; set;}
public string Name {get; set;}
public virtual List<Workout> Workouts {get; set;}
public virtual List<TrainingPlan> TrainingPlans {get; set;}
}
public class Workout
{
public int Id {get; set;}
public string Name {get; set;}
public virtual Athlete Athlete {get; set;} //Athlete owner of the WO.
public virtual List<TrainingPlan> TrainingPlans {get; set;} //Plans where WO is.
}
public class TrainingPlan
{
public int Id {get; set;}
public string Name {get; set;}
public virtual Athlete Athlete {get; set;} //Athlete owner of this TP.
public virtual List<Workout> Workouts {get; set;} //Workouts in this plan.
}
因为我需要额外的字段,所以我读到SO应该向Entity推广这种关系,这就是我这样做的结果:
public class TrainingPlanWorkout
{
public int Id {get; set;}
public virtual TrainingPlan TrainingPlan { get; set; }
public virtual Workout Workout { get; set; }
public DateTime DateToPerform { get; set; }
}
现在使用fluen't API我定义了所有这些:
//I define primary keys.
modelBuilder.Entity<Athlete>().HasKey(x => x.Id);
modelBuilder.Entity<TrainingPlan>().HasKey(x => x.Id);
modelBuilder.Entity<Workout>().HasKey(x => x.Id);
modelBuilder.Entity<TrainingPlanWorkout>().HasKey(x => x.Id);
modelBuilder.Entity<Athlete>().HasMany(a => a.AthleteTrainingPlans)
.WithRequired(t=>t.Athlete)
.WillCascadeOnDelete(true);
modelBuilder.Entity<Athlete>().HasMany(m => m.AthleteWorkouts)
.WithRequired(m=>m.Athlete)
.WillCascadeOnDelete(true);
modelBuilder.Entity<TrainingPlanWorkout>().HasRequired(t => t.TrainingPlan);
modelBuilder.Entity<TrainingPlanWorkout>().HasRequired(t => t.Workout);
当我运行应用程序时,我收到以下错误:
引入FOREIGN KEY约束 桌上的'FK_dbo.TrainingPlanWorkouts_dbo.Workouts_Workout_Id' 'TrainingPlanWorkouts'可能会导致循环或多个级联路径。 指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他 FOREIGN KEY约束。
我认为我过于复杂化了,完成这种情况的最佳方式是什么?
感谢。
答案 0 :(得分:1)
我使用以下代码实现了您的问题,主要区别在于关系实体的modelBuilder。
namespace ConsoleApplication1
{
class Program
{
public class Athlete
{
public int Id { get; set; }
public string Name { get; set; }
private ICollection<Workout> workouts;
public virtual ICollection<Workout> Workouts
{
get { return workouts ?? (workouts = new HashSet<Workout>()); }
set { workouts = value; }
}
private ICollection<TrainingPlan> trainingPlans;
public virtual ICollection<TrainingPlan> TrainingPlans
{
get { return trainingPlans ?? (trainingPlans = new HashSet<TrainingPlan>()); }
set { trainingPlans = value; }
}
}
public class TrainingToPerform
{
public int Id { get; set; }
public DateTime DateToPerform { get; set; }
public virtual TrainingPlan TrainingPlan { get; set; }
public virtual Workout Workout { get; set; }
}
public class Workout
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Athlete Athlete { get; set; }
private ICollection<TrainingToPerform> trainingsToPerform;
public virtual ICollection<TrainingToPerform> TrainingsToPerform
{
get { return trainingsToPerform ?? (trainingsToPerform = new HashSet<TrainingToPerform>()); }
set { trainingsToPerform = value; }
}
}
public class TrainingPlan
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Athlete Athlete { get; set; }
private ICollection<TrainingToPerform> trainingsToPerform;
public virtual ICollection<TrainingToPerform> TrainingsToPerform
{
get { return trainingsToPerform ?? (trainingsToPerform = new HashSet<TrainingToPerform>()); }
set { trainingsToPerform = value; }
}
}
public class Db3 : DbContext
{
public Db3()
{
}
public DbSet<Athlete> Athletes { get; set; }
public DbSet<Workout> Workouts { get; set; }
public DbSet<TrainingPlan> TrainingPlans { get; set; }
public DbSet<TrainingToPerform> TrainingsToPerform { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<TrainingPlan>()
.HasKey(x => x.Id);
modelBuilder.Entity<Workout>()
.HasKey(x => x.Id);
modelBuilder.Entity<Athlete>()
.HasKey(x => x.Id);
modelBuilder.Entity<Athlete>()
.HasMany(a => a.TrainingPlans)
.WithRequired(t => t.Athlete)
.WillCascadeOnDelete(true)
;
modelBuilder.Entity<Athlete>()
.HasMany(a => a.Workouts)
.WithRequired(t => t.Athlete)
.WillCascadeOnDelete(true)
;
modelBuilder.Entity<TrainingToPerform>()
.HasKey(x => x.Id);
modelBuilder.Entity<TrainingToPerform>()
.HasRequired(t => t.Workout)
.WithOptional()
.WillCascadeOnDelete(false)
;
modelBuilder.Entity<TrainingToPerform>()
.HasRequired(t => t.TrainingPlan)
.WithOptional()
.WillCascadeOnDelete(false)
;
}
}
static void Main(string[] args)
{
var db = new Db3();
var a = new Athlete { Name = "a6"};
var w = new Workout { Name = "w6", Athlete = a };
var t = new TrainingPlan { Name = "t6", Athlete = a };
db.Athletes.Add(a);
db.Workouts.Add(w);
db.TrainingPlans.Add(t);
db.SaveChanges();
var wtp = new TrainingToPerform { TrainingPlan = t, Workout = w, DateToPerform = DateTime.Now };
w.TrainingsToPerform.Add(wtp);
t.TrainingsToPerform.Add(wtp);
db.TrainingsToPerform.Add(wtp);
db.SaveChanges();
Console.WriteLine(db.TrainingsToPerform.First().Workout.Name);
}
}
}
答案 1 :(得分:0)
我能想到的另一件事是将所有关系转移到一个新的班级ATrainingAthlete
,这个班级只会将运动员的训练和训练计划汇集在一起。
public class Athlete
{
public int Id {get; set;}
public string Name {get; set;}
//public virtual List<Workout> Workouts {get; set;}
//public virtual List<TrainingPlan> TrainingPlans {get; set;}
}
public class Workout
{
public int Id {get; set;}
public string Name {get; set;}
//public virtual Athlete Athlete {get; set;} //Athlete owner of the WO.
//public virtual List<TrainingPlan> TrainingPlans {get; set;} //Plans where WO is.
}
public class TrainingPlan
{
public int Id {get; set;}
public string Name {get; set;}
//public virtual Athlete Athlete {get; set;} //Athlete owner of this TP.
//public virtual List<Workout> Workouts {get; set;} //Workouts in this plan.
}
public class ATrainingAthlete
{
public int Id {get; set;}
// connect the athlete
public virtual Athlete Athlete {get; set;}
// with its workouts
public virtual List<Workout> Workouts {get; set;}
// and training plans
public virtual List<TrainingPlan> TrainingPlans {get; set;}
}