我一直在重新审视我使用实体的方式,我需要建议。
我正在创建一个瑜伽预订服务,每个用户都会有一个简介,空间来满足瑜伽和活动,并有一个日期和时间,以便每个空间聚会。
所以我的关系看起来像这样,他们都是一对多的
YogaProfile -> YogaSpace(s) -> YogaSpaceEvent(s)
创建活动时,会员(YogaProfiles
)可以加入任何人的活动。有点像一个班级。它是一个注册/调度系统。
最初我创建了一个名为RegisterdStudents
的表,并将该集合添加到YogaSpaceEvent
。喜欢这个
public class YogaSpaceEvent
{
// other code here left out
public virtual ICollection<RegisteredStudent> RegisteredStudents { get; set; }
}
和RegisteredStudent
看起来像这样
public class RegisteredStudent
{
[Key]
public int RegisteredStudentId { get; set; }
[Index]
public int YogaSpaceEventId { get; set; }
[ForeignKey("YogaSpaceEventId")]
public virtual YogaSpaceEvent YogaSpaceEvent { get; set; }
[Index]
public int StudentId { get; set; }
}
这一切都很好,但后来我学到了更多关于多对多的知识,并认为我可能需要在这里使用它,因为许多配置文件可以注册一个事件,许多事件可以注册到一个配置文件ex。一个班级可以有很多人参加,学生可以参加很多班级。
所以我通过在两个实体(virtual ICollection
,YogaProfile
)中的每一个上创建YogaSpaceEvent
并创建一个名为的连接表来更改代码以建立多对多关系RegisteredStudentInEvent
喜欢这个
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<YogaProfile>()
.HasMany<YogaSpaceEvent>(x => x.YogaSpaceEvents)
.WithMany(x => x.RegisteredStudents)
.Map(x =>
{
x.MapLeftKey("YogaProfileId");
x.MapRightKey("YogaSpaceEventId");
x.ToTable("RegisteredStudentInEvent");
});
}
现在,我可以成功地将多个学生(YogaProfile
)添加到一个班级(YogaSpaceEvent
),在表格中,我会看到包含活动(YogaSpaceEventId
)的行以及&#39;已注册(YogaProfileId
)。
但是现在,看看这种多对多关系设置,我发现我不需要像下面那样向学生(YogaSpaceEvent
)添加多个班级(YogaProfile
),因为YogaSpaceEvents
已添加到YogaSpaces
上的集合,而不是YogaProfile
yogaProfile.YogaSpaceEvents.Add(yogaSpaceEvent)
所以我的问题是,我应该回到我最初做的方式还是继续使用这种多对多模型?什么是差异,专业,缺点等?
答案 0 :(得分:0)
在进一步观察和发现后,我认为这可能是最好的解决方案。
保留我的原始&#39; RegsiteredStudent&#39;实体,但让它看起来像这样
public class RegisteredStudent
{
public RegisteredStudent() { }
[Key]
public int RegisteredStudentId { get; set; }
[Key]
[Column(Order = 1)]
public int YogaProfileId { get; set; }
[Key]
[Column(Order = 2)]
public int YogaSpaceEventId { get; set; }
[ForeignKey("YogaProfileId")]
public YogaProfile YogaProfile { get; set; }
[ForeignKey("YogaSpaceEventId")]
public virtual YogaSpaceEvent YogaSpaceEvent { get; set; }
}
这样我就可以将注册学生(YogaProfile)添加到像这样的新活动中
yogaSpaceEvent.RegsiteredStudents.Add(yogaProfile);
我们应该对参考文献都很满意,这样我就可以查找谁...
答案 1 :(得分:0)
如果我错了,请纠正我,但在我看来,个人资料代表一个人。在个人资料可能参加的特定时间内,事件代表瑜伽课程。而Space就是此次活动的举办地点。
空间与事件之间存在一对多关系:在一个地方可能会举行许多活动。每个活动都在一个地方举行。
个人资料和事件之间存在多对多关系:每个个人资料都可以参加许多活动,每个活动都可能有很多个人资料参加。
例如,事件E1保留在空间S1。决定参加活动E1的每个个人资料,他都应该去太空S1。这不应该记录在配置文件中。如果将事件E1移动到另一个空间,例如S2,则只需更改一条记录:与事件和空间相关的记录。这一个更改将使参加E1的所有个人资料都可以看到他们应该转到S2,尽管个人资料中没有任何内容发生变化。
所以我不明白为什么你需要Profiles和Spaces之间的关系。我非常确定,对于定义良好的数据库中的预订服务,您最好不要在个人档案和空格之间建立这样的关系
所以:
这为您提供了类似以下的课程。
class Space
{
public int Id {get; set;}
// zero or more Events are held at this Space:
public virtual ICollection<Event> Events {get; set;}
... // other properties
}
class Event
{
public int Id {get; set;}
// every event takes place at exactly one Space using foreign key
public int SpaceId {get; set;}
public virtual Space Space {get; set;}
// every Event is attended by zero or more Profiles (many-to-many)
public virtual ICollection<Profile> Profiles {get; set;}
public DateTime StartTime {get; set;}
public TimeSpan Duration {get; set;}
... // other properties
}
class Profile
{
public int Id {get; set;}
// every Profile attend zero or more Events (many-to-many)
public virtual ICollection<Event> Events {get; set;}
... // other properties
}
最后是DbContext:
public MyDbContext : DbContext
{
public DbSet<Event> Events {get; set;}
public DbSet<Space> Spaces {get; set;}
public DbSet<Profile> Profiles {get; set;}
}
因为我遵循entity framework code first conventions,所以实体框架需要知道您打算实现一对多和多对多关系。实体框架将创建多对多关系所需的外键和额外连接表。不需要Attributes或Fluent API。只有当您需要不同的表名或列名时,您才需要流畅的API或属性。
没有保障在同一时间在同一空间举行两个不同的活动。如果你想要,你应该给每个空间零个或多个TimeSlots(每个TimeSlot只属于一个空格)。
为了让事情变得简单,我每个时间段都要花一个小时。超过一小时的事件需要多个TimeSlots
class TimeSlot
{
public int Id {get; set;}
public long Hour {get; set;}
// TODO: create a function from Hour to DateTime
// every TimeSlot is a TimeSlot of exactly one Space using foreign key
public int SpaceId {get; set;}
public virtual Space Space {get; set;}
// every TimeSlot is used by one Event using foreign key
public int EventId {get; set;}
public Event Event {get; set;}
}
现在,一个事件在一个或多个TimeSlots中保存(它们是某个空间的TimeSlots)。因此,如你所愿,可以在一个空间或几个空间举行一个多小时的活动
要在特定时间内在特定空间创建活动,请询问Space是否在请求的时间内有TimeSlots。如果是这样,空间就被占用了。如果没有,空间是免费的。
所以,如果我想创建一个活动,例如晚间课程,从20:00到21:00之间的3个星期三晚上,从2018年5月1日开始,将这三次转换为小时:
IEnumerable<long> hours = ... // the three times the course will start
// find a space that has not any TimeSlots during these hours
Space freeSpace = myDbContext.Spaces
.Where(space => !space.TimeSlots
.Select(timeSlot => timeSlot.Hour)
.Union(hour)
.Any())
.FirstOrDefault();
if (freeSpace != null
{ // this Space has no TimeSlot at any of the three hours,
// create an time slots in this Space
IEnumerable<TimeSlot> timeSlots = myDbContext.TimeSlots.AddRange(hours
.Select(hour => new TimeSlot()
{
Hour = hour,
Space = freeSpace,
})
.ToList());
// create an Event to be held at these TimeSlots (and thus at the FreeSpace
var event = myDbContext.Add(new Event()
{
TimeSlots = timeSlots.ToList();
Description = ...
...
});
让以下个人资料参加此活动:
IEnumerable<Profile> profilesWishingToAttend = ...
foreach (Profile profileWishingToAttend in profilesWishingToAttent)
{
profileWishingToAttend.Events.Add(event);
}
您可以将个人资料添加到活动中,而不是将事件添加到“个人资料”中:
IEnumerable<Profile> profilesWishingToAttend = ...
foreach (Profile profileWishingToAttend in profilesWishingToAttent)
{
event.Profiles.Add(profileWishingToAttend);
}