Reputation: 1832
I have a .net solution (with Entity Framework, using the CodeFirst approach) about the administration of a university. The architecture of the project is like this:
For making the question easier, i'll only talk about two classes from my domain (on the Entities layer):
The course can have many students. And the objective of the solution, is to add students to the courses (with some validation in the middle).
Course.cs
public class Course
{
[Key]
public int IdCourse { get; protected set; }
public string Name { get; set; }
public virtual ICollection<Student> Students { get; protected set; }
public void AddStudent(Student student)
{
// Some Validation
Students.Add(student);
}
}
As you can see, the class has a property for adding students to the course. The situation is that the validation is growing and now is very complex, and it needs to make some queries to the database and more... So the course have a lot of responsibilities!
So i thought, that i needed a service for handling the "Adding" and making all the validation and take this reponsibility away from the Course class. The problem is that, as the Students Collection is a private member from Course, i can't add students to courses from the Service class.
Another way i thought to solve the problem, is adding the related entity (the student) to the context (from the service), but it would break my repository (because i would have to make the DbContext public). And if i use the DbContext from the Service class directly, the repository has no point, hasn't it?
So, how should i design that? or what should i do to solve the problem? Any suggestion would be very well received too!
Thanks!
Upvotes: 1
Views: 99
Reputation: 19881
I don't agree with a method like AddStudent(...)
in the entity. Let entities be simple data transfer objects - that is, POCOs - into and out of the EntityFramework. I prefer to let my business logic take care of such things.
You can set the IdCourse
and Students
setter to private. I have seen others use protected
as well ... but why? Are there descendants of an entity?
One solution for ICollection<T>
properties recommended by the likes of Julie Lerman is:
private ICollection<Student> _students;
public virtual ICollection<Student> Students {
get; { _students ?? (_students = new Collection<Student>()); }
private set { _students = value; }
}
Update (from comment)
If you use a repository or business layer to query for a Course, you could have a method as follows:
// this is how I would approach a business layer method
void AddStudentToCourse(string CourseName, Student NewStudent) {
// may employ a using block for repository
// also validate student
using (var repo = new CourseRepository()) {
var course = repo.GetCourse(CourseName);
course.Students.Add(NewStudent);
repo.Save();
}
}
There are a few different ways to accomplish this and this sample is far from complete but should provide you with a basic concept.
The underlying DbContext
(either inherited or encapsulate by CourseRepository
) will track changes to Course
and the addition of a new student or relationship of the Student
to the Course
.
As far as the use of private or protected setters, I wanted to limit developer access to changing IDs/Keys or reassigning entire collection references.
Upvotes: 0
Reputation: 181
This doesn't directly answer your question, especially as related to code-first EF and all that (not my area of expertise). But it does look like you have a design issue here.
I'm a big fan of DDD, or Domain-Driven Design. Some questions you might want to ask include:
There are others, but definitely take a holistic look at your problem and the way your objects are designed. Is adding a student the course the same as adding the course to that student?
Maybe your service could do the validation and either add the student to the course, or the course to the student (or both) and persist them in their own repositories.
In any event, I'd recommend Julie Lerman's series on DDD for data-oriented EF people: http://msdn.microsoft.com/en-us/magazine/dn342868.aspx.
In any event, I would recommend not making your DbContext public!
Upvotes: 1