2

我有这个模型。一名运动员有多项锻炼和多项训练计划。锻炼可以在许多训练计划中。一天可以进行多次锻炼,这就是为什么我需要 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; }
}

现在使用流利的 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);

当我运行应用程序时,我收到以下错误:

在表“TrainingPlanWorkouts”上引入 FOREIGN KEY 约束“FK_dbo.TrainingPlanWorkouts_dbo.Workouts_Workout_Id”可能会导致循环或多个级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。

我想我把事情复杂化了,完成这种情况的最佳方法是什么?

谢谢。

4

2 回答 2

1

我使用以下代码实现了您的问题,主要区别在于关系实体的模型构建器。

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);

        } 
    }
}
于 2014-08-01T10:16:46.183 回答
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;}
}
于 2014-07-31T15:45:14.387 回答