Sverker84
Sverker84

Reputation: 465

Complex relationships / access control with ASP.NET MVC 3 and EF 4.1 and POCO

I am working on a project with the following conditions:

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

Upvotes: 2

Views: 272

Answers (2)

Betty
Betty

Reputation: 9189

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.

public class User {
  ICollection<FacilityTask> FacilityTask {get; set;}
}

public class FacilityTask {
  public Facility Facility {get; set;}
  public Task Task {get; set;}
}

or 

public class FacilityTasks {
  public Facility Facility {get; set;}
  public ICollection<Task> Task {get; set;}
}

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.

Upvotes: 2

Ivo
Ivo

Reputation: 8352

Question: Facilities have Tasks and the user can have Facilities and Tasks that are not related each other? If so, which name will you put to that table you suggested? You can create a class with that "name".

If not, your user can just have a collection of Tasks and you can access the Facilities doing

return Tasks.Select(x => x.Facility).Distinct();

Another option is to have both collections in your User class.

Upvotes: 0

Related Questions