I am working on a project with the following conditions:
- Visual Studio 2010
- ASP.NET MVC 3
- EF 4.1 (can use something else if recommended)
- Code first
I am trying to model the following, but I stuck in my thinking on how to do it best.
I have these objects.
public class Facility
{
public virtual int FacilityId;
public virtual string Name;
public virtual List<TaskCategory> TaskCategories;
}
public class TaskCategory
{
public virtual int TaskCategoryId;
public virtual string Name;
}
public class User
{
public virtual int UserId;
public virtual string Username;
}
Facility and TaskCategory is a many-to-many relationship
Facility and User is a one-to-many relationship (one facility can have many users, one user can belong only to one facility)
Now I need some way to connect these three objects so that the following conditions are met:
– In the system, one should be able to connect a user to a certain facility AND certain TaskCategory
In a traditional database I would model it like this:
User_id, Facility_id, TaskCategory_id
1, 1, 1
1, 1, 2
2, 1, 1
1, 2, 1
Which means that user 1 will have access to TaskCategories 1 and 2 in Facility 1 and TaskCateogry 1 in Facility 2.
User 2 will have access to TaskCategory 1 in Facility 1.
Does this make sense, and how would I do this in an object-oriented environment that works with EF 4.1 (or other ORM).
UPDATE:
The following code is what I ended up using (some irrelevant pieces not included here):
public class Facility
{
public int Id { get; set; }
public string Name { get; set; }
private ICollection<FacilityMembership> _facilityMembership;
public virtual ICollection<FacilityMembership> FacilityMembership
{
get { return_facilityManager ?? (_facilityManager = new HashSet<FacilityMembership>(); }
set { _facilityManager = value; }
}
}
}
public class TaskCategory
{
public int Id { get; set; }
public string Name { get; set; }
private ICollection<FacilityMembership> _taskMemberships;
public virtual ICollection<FacilityMembership> TaskMemberships
{
get { return _taskMemberships?? (_taskMemberships= new HashSet<FacilityMembership>()); }
set { _taskMemberships = value; }
}
}
public class User
{
public int Id { get; set; }
public string Username { get; set; }
private ICollection<FacilityMembership> _facilityMembership;
public virtual ICollection<FacilityMembership> FacilityMembership
{
get { return_facilityManager ?? (_facilityManager = new HashSet<FacilityMembership>(); }
set { _facilityManager = value; }
}
}
public class FacilityMembership
{
public int Id { get; set; }
public int FacilityId { get; set; }
public int UserId { get; set; }
private ICollection<TaskCategory> _taskCategories;
public virtual ICollection<TaskCategory> TaskCategories
{
get { return _taskCategories ?? (_taskCategories = new HashSet<TaskCategories>()); }
set { _taskCategories = value; }
}
}
And then mapping via fluent api:
modelBuilder.Entity<FacilityMembership>().HasKey(fm => fm.Id);
modelBuilder.Entity<FacilityMembership>()
.HasMany(fm => fm.TaskCategories)
.WithMany(tc => tc.FacilityMemberships)
.Map(m =>
{
m.MapLeftKey("FacilityMembershipId");
m.MapRightKey("TaskCategoryId");
});
Your traditional database model suggests it is a many-to-many relationship (user to facility) with additional properties (tasks). There is no magic way to do this in EF, it’s simply the same as you would in a database, with an extra table/entity.
There may be a better naming scheme than FacilityTasks, perhaps a FacilityMembership? A user belongs to a Facility and there are tasks associated to that membership.