MVC (Spring): Logic Organisation Entity and Service - spring

I have a simple question about code organisation.
TeamRepository (Repository Class)
TeamService (Service Class)
Team (Entity Class)
I want to set a new team leader for an team object. Should this function "setLeader(User user)" in the Entity Class or better in the TeamService Class?
team.setLeader(user);
teamService.save(team);
or
teamService.setLeader(team, user);
Inside the "setLeader" Function there is a if condition (if user is a team member) then declare the user as the new team leader.
I guess it's ok in the entity class or? I am confused because i have read that "business logic" should not be in entity classes.
Best regards

Kindly keep in mind that:
Entity Class:
In a good designed architecture, it should be just like a POJO class, containing simple attributes, default constructor, their getter() & setters() and other optional methods like toString() & equal() etc.
Example:
#Entity
public Class Team{
private String id;
private User leader;
public Team(){}
//getters & setters
}
Repository Class:
This main purpose of this class should be either save, update, delete or retrieve simple record from a database, no business logic.
Service Class:
This is the class where you can specify all business/ domain related logic here. It should populate required entity object, and then call specific repository class to save given entity.
#Service
public class TeamService{
#Autowired
TeamRepository repo;
public void createTeam(){
Team team = new Team();
if(//user is the member of team){
team.setLeader(user);//assume user object is already initialized
}
repo.save(user);
}
}

Since leader is a attribute of your Team-class, leader should be directly manipulated with the setter-method of your Team-class. That's my opinion/feeling.
There is no higher logic or computation behind the action. It's just setting the value of the entity's attribute.

Related

What is the right design to have a spring Entity that is different than what the REST API returns?

Right now, I have an #Entity say Car that has a certain set of attributes. This gets persisted into a database.
Now, in the #RestController, if I want to accept a Car parameter except for certain properties, how do I do that? Right now, I am creating a different class called CarInput that is the same as Car minus those properties.
Again, for REST API response, same thing. If I want to return a Car but with a certain field removed. Right now I created CarResponse as a model.
Is there a cleaner way to do this?
I'd make the case that your external representation and your internal storage should hardly ever be identical. Sure, there'll be significant overlap, but your database and your API should be as independent from each other as possible.
I'd say it's a good practice to have separate domain models for the model and view layer (read: two different Car classes, in different packages). You can use a mapping framework like Dozer or MapStruct to map back and forth between these different entity types.
There are two common approaches to such problem.
Use #JsonIgnore on fields/getters that you want to exclude. However, this can lead to annotation hell or generally hard to read code.
#JsonIgnore
private String password;
Create a DTO class that data would be deserialized from or serialized to. What I mean is that when some user makes a POST request with a car definition, it would be deserialized by spring to CarDto and then parsed by you in the service layer to the Car object which you could save to a database. Similarly, Car object would be parsed to CarDto if the user asks for a data.
#GetMapping("/{userId}")
UserDto getUser(#PathVariable Long userId) {
return userService.getUser(userId);
}
#PostMapping
UserDto addUser(#RequestBody UserDto userDto) {
return userService.createUser(userDto);
}
This one, on the other hand, could lead to a situation where you sometimes use a Dto and sometimes the class itself. Because of that, consider parsing to/from CarDto only in the controller layer (unlike in the example above)
Also it's good to avoid creating two classes in one file. It makes hard to find a desired class afterwards.
You can still avoid of using a DTO class.
When you post Car object to controller your can control the wanted properties and operate on it.
For selecting fields to return as the response you can use json views.
Entity :
public Car {
private String color;
#JsonView(Views.Public.class)
private Integer weight;
// getters, setters
}
Controller :
#RestController
public CarController
#Autowired
private CarRepository carRepository;
#GetMapping("/{id}")
#JsonView(View.Public.class)
public Book get(#PathVariable Long id){
return carRepository.findOne(id);
}
#PostMapping
public Book update(#RequestBody Car car) {
// only properties we want to update
if(car.getColor() != null) {
// save in database or other operations
}
}
}
View :
public class Views {
public static class Public {
}
}
This way the controller's method "get" will send to client only "weight" property and "update" method will operate only on selected properties.

Common shared data objects for entire application

I have some data objects that are common across a Spring boot application - one is the logged in employee object and other is a category. I have created a #Component class which contains these are static variables. This way I do not even have to autowire them. They can be used directly like CurrentContext.employee in controllers.
#Component
public final class CurrentContext {
public static Category currentCategory;
public static Employee employee;
#Autowired
private CategoryService categoryService;
#Autowired
private EmployeeService employeeService;
#EventListener
public void onApplicationEvent(ContextRefreshedEvent event) {
currentCategory = categoryService.getCategory();
}
#EventListener
public void onLoginSuccess(InteractiveAuthenticationSuccessEvent event) {
employee = employeeService.getEmployeeByUserId(((MyUserDetails) event.getAuthentication().getPrincipal()).getUserId());
}
}
Is this a right way? Please suggest if there is a better way to handle shared data
Edit
Some background - I require the current logged in employee and a category which is common for all employees. So I autowired employeeService and categoryService in my controllers and use them to get the data. They are required in almost all my controller methods, so, I wanted to create a bean of these so that I directly use them in my controller and also save frequent database calls.
Normally, we only put the dependencies related to the cross-cutting concerns (i.e dependencies that are across the whole application such as security , logging , transaction stuff , time provider etc.) in the static field.
By accessing these kind of dependencies in the static way , we don't need to pass them through method parameters /constructors from object to object , which will make the API much cleaner without such noise (BTW. This is called Ambient Context Pattern in the .NET world).
Your Employee object most probably belong to this type , so it is ok to access it in a static way. But as their scope is per session , you cannot simply put it in the static field of a class. If yes, then you always get the same employee for all sessions. Instead, you have to somehow store it in an object which is session scope (e.g HttpSession) . Then at the beginning of handling a web request , you get it from the session and then put it in a ThreadLocal which is encapsulated inside a "ContextHolder" object. You then access that "ContextHolder" in a static way.
Sound very complicated and scary ? Don't worry as Spring Security has already implemented this stuff for you. What you need to do is to customize Authentication#getPrincipal()or extend default Authentication to contain your Employee. Then get it using SecurityContextHolder.getContext().getAuthentication()
For your currentCategory , if they are not the cross-cutting concerns and is the application scope , make a singleton bean to get it values is a much better OOP design.
#Component
public final class CurrentCategoryProvider {
#Autowired
private CategoryService categoryService;
public Category getCurrentCategory(){
//or cache the value to the an internal properties depending on your requirements
return categoryService.getCategory();
}
}
You then inject CurrentCategoryProvider to the bean that need to access currentCategory.

How to decouple repository and entities

This is a question on domain model design.
Let's say for a domain design involving users and groups, we have the following interfaces to implement:
interface IUser
{
string Name{get;}
DateTime DOB {get;}
}
interface IGroup
{
string Name {get;}
bool IsUserInGroup(IUser user); // #1
void IncludeUser(IUser user); // #2
void ExcludeUser(IUser user); // #3
}
interface IUserRepository
{
IUser Create(string name);
IUser GetByName(string name);
void Remove(IUser user);
void Save(IUser user);
}
interface IGroupRepository
{
IGroup Create(string name);
IGroup GetByName(string name);
void Remove(IGroup group);
void Save(IGroup group);
}
The tricky bit is to implement #1 #2 and #3 while keeping the entity classes (User, Group) decoupled from the repository classes (UserRepository, GroupRepository.)
Another technicality to consider is that most RMDB systems do not implement many-to-many relationships, and in practice there is always a separate table (say, UserGroupAssociation) to have records each associates a user and a group via foreign keys. I would like to hide this implementation detail from the domain interfaces and expose the equivalent logic through members #1 #2 and #3.
The effect of calling #2 and #3 should not persist until the group object in question has been saved (i.e. passed to the Save() method of the repository object)
How do you usually do it?
I don't do it. My Repository objects are tightly coupled to the root of the aggregate to which they relate, and (as kind of an aside) I don't bother making interfaces for my domain model objects unless I find I have a good reason to do so - do you have a particular reason to do this?
I've not come across any Repository examples which don't use the entity implementation type in the repository class (this one, for instance) and can't think of any real advantage of using an interface instead. Interfaces earn their keep for infrastructure components (like a Repository) by making it easier to mock out entire layers of the system when testing, you don't get the same type of advantage using interfaces for domain objects.
And to perhaps actually answer the question...
I never have a domain object access a Repository - the domain object after all is supposed to represent something in the domain in real life, and Repositories are infrastructure components that don't exist in real life, so why would a domain object know about one?
For the specific example of adding a User to a Group, I'd use a Service Layer class, and do this:
public class UserService
{
private readonly IGroupRepository _groupRepository;
private readonly IUserRepository _userRepository;
public UserService(
IGroupRepository groupRepository,
IUserRepository userRepository)
{
this._groupRepository = groupRepository;
this._userRepository = userRepository;
}
public void IncludeUserInGroup(string groupName, string userName)
{
var group = this._groupRepository.FindByName(groupName);
var user = this._userRepository.FindByName(userName);
group.IncludeUser(user);
this._userRepository.SaveChanges();
}
}
public class User
{
public void AddToGroup(Group group)
{
this.Groups.Add(group);
}
public void RemoveFromGroup(Group group)
{
this.Groups.Remove(group);
}
}
Some points to note:
To avoid lazy-loading large numbers of Users when adding a User to a Group I've moved the Group administration methods onto User - depending on how much behaviour you actually have for Group, you might even consider turning it into an enumeration rather than a class. Be aware that if you're using the Entity Framework POCO T4 Templates with FixupCollections, this will still lazy-load all the Users in a Group, but you can get around that in one way or another :)
The Service Layer class would implement a Create() method, the like of which you have on your Repositories. The Repositories would have an Add method, Find methods and a SaveChanges() method. Add would add an object created by the Service Layer to the object context.
All Repository classes would be set up to use the same underlying, request-scoped object context, so it wouldn't matter which one you call SaveChanges() on.
SaveChanges() would cause all changes which had happened to objects during that request to be saved, such as a User having a new Group's added to their Groups collection.
Finally, another good technique for decoupling entities from Repositories and other infrastructure components is Domain Events.

ASP.Net MVC 3 - What is the best way to get logged-in username from within the repository?

I know that you can get the username of the currently logged in user from within the controller by using User.Identity.Name. However, my solution is split in 4 layers (4 projects):
MyProject.Domain for the models
MyProject.Data for the repositories
MyProject.Services where the business logic is
MyProject.Web for the controllers, the ViewModels and the Views
Now, my question is what is the best way the get the username of the current user from within the repository.
The thing is that all my models have 4 audit properties: CreatedBy, CreatedDate, ModifiedBy, ModifiedDate. And I am wondering how to populate the CreatedBy and the ModifiedBy properties when a model is stored to the database.
UPDATE:
Here is what I did following the advices I got below. I added an IUser interface in my Domain. I am not sure whether this is the best place to add this, but I decided to put it there, since my domain in referenced by all my other layers. I also added a User class to my controller layer (MyProject.Web), since this class needs access to the HttpContext, and this is the layer where it is accessible. To tell the truth, I did not know where such a class should be added in this layer. I have a Lib directory, so I put it in there.
Then I added a binding in MyProject.Web.App_Start.NinjectMVC3 like this:
private static void RegisterServices(IKernel kernel)
{
...
kernel.Bind<IUser>().To<User>();
}
I also added an IUser parameter to my base repository class constructor like this:
public abstract class RepositoryBase<T> where T : class, IEntity
{
#region Members
private UpDirContext dataContext;
private readonly IDbSet<T> dbset;
private readonly IUser user;
#endregion
protected RepositoryBase(IDatabaseFactory databaseFactory, IUser user)
{
DatabaseFactory = databaseFactory;
dbset = DataContext.Set<T>();
this.user = user;
}
...
So now, I can use "user" everywhere in my repositories. It is working, but I am not sure whether this is the best way of structuring things.
I also thought that I could use injection to pass IUser to my base entity class and make sure that the CreatedBy and ModifiedBy properties of my entities would be populated properly from the start, meaning object construction, but then my entities would not have had a constructor with zero parameter, and I did not want that.
UPDATE 2:
Here is an example of one of my services constructor:
public partial class SectorService : ISectorService
{
private readonly ISectorRepository sectorRepository;
private readonly IUnitOfWork unitOfWork;
public SectorService(ISectorRepository sectorRepository, IUnitOfWork unitOfWork)
{
this.sectorRepository = sectorRepository;
this.unitOfWork = unitOfWork;
}
...
I already use injections to get the repositories to the service layer. According to a comment below, IUser should be injected to the service layer, and I am wondering what is the best method to get User passed from this layer to the repositories.
Using dependency injection, inject an IUser at your composition root (ie your controller's constructor - all the main DI containers support it plius mvc supports it). The concrete implementation of IUser references HttpContext.Current.User.Identity.Name. All of the receivers of IUser don't need to care about where it came from.
I'm not following why though you asked about createdby, etc. Is this a separate question or are you referring to membership information?
My practice as of late is to pass it from controller -> service, then service -> repository, if necessary. This is because I want two websites (think public facing website and private API website) to use the same models/repositories/services, but the authentication methods for each are different.

How to execute Queries with multiple models in Entity framework with Dependency Injection

I tried using Dependency Injection with Entity framework in my MVC application. In the project I have defined Generic Repository class for CRUD operations. There are concrete service classes for each model object. My Controller in Presentation layer uses Concrete classes of Service layer to get data from database. These concrete classes in turn calls RepositoryClass methods to implement actual operation with database.
Below is sample of the class definations (for simplicity I have removed various interfaces details and implementation of some methods):
class RepositoryBase<T>
{
Add(T entity) {...}
Update (T entity) {...}
Delete (T entity) {...}
T GetById(int id) {...}
IEnumerable<T> GetAll()
{dbContext.ToList();}
}
public class CarsService {
public IEnumerable<Cars> GetCars()
{
var cars = RepositoryBase<Cars>.GetAll();
return cars;
}
public Car GetCar(int id)
{
var car = RepositoryBase<T>.GetById(id);
return car;
}
}
Public class DealerService {...}
All this works great as long as I have to deal with 1 object type at a time in my application. But I am not sure how to make change in service class to get data for multiple entities i.e. Car and dealers togather. Please note in my scenario although i have dealer id defined in Cars model but navigation property is missing. So I have to join Cars and Dealers using linq query.
Please help to identify correct class (layer) which needs to be modified. All the examples I have found only talks about 1 entity at a time.
DbContext.Set().Include()first of all you put you config mapping for fixing,
second if you don't want to use navigation properties , you can use
RepositoryBase<Cars>.GetEntitySet<Cars>.Include("Dealers") //this does join if you key to join
but in this case you should use the
add to RepositoryBase<T> a property
public ISet<T> GetEntitySet<T>(string table2Include)
{
return DbContext.Set<T>()
}

Resources