I have a situation where I have another DTO in inside a DTO to which I have to map to its corresponding entity.
I am using mapstruct and I already have AnotherEntityMapper already existing.
DTO
public class EntityDTO {
private AnotherEntityDTO anotherEntityDTO;
// other fields
}
Entity
#Entity
public class Entity {
private AnotherEntity anotherEntity;
// other fields
}
How to change the EntityMapper interface, so that I can map anotherEntityDTO to anotherEntity?
Thanks.
It really depends which version of MapStruct you are using. If you are using 1.2.0.Beta or higher they you can just define the nested properties on your EntityMapper interface:
#Mapper
public interface EntityMapper {
#Mapping(target = "anotherEntity", source = "anotherEntityDTO")
#Mapping(target = "anotherEntity.propE", source = "anotherEntityDTO.propD")
Entity map(EntityDDTO dto);
}
Another option (and a must if you are using version less than 1.2.0.Beta) is to add a new Method in your EntityMapper like:
#Mapper
public interface EntityMapper {
#Mapping(target = "anotherEntity", source = "anotherEntityDTO")
Entity map(EntityDDTO dto);
#Mapping(target = "propE", source = "propD")
AnotherEntity map(AnotherEntityDTO);
}
or you can define a new Mapper AnotherEntityMapper for the AnotherEntity and use #Mapper(uses = {AnotherEntityMapper.class}):
#Mapper
public interface AnotherEntityMapper {
#Mapping(target = "propE", source = "propD")
AnotherEntity map(AnotherEntityDTO);
}
#Mapper(uses = {AnotherEntityMapper.class}
public interface EntityMapper {
#Mapping(target = "anotherEntity", source = "anotherEntityDTO")
Entity map(EntityDDTO dto);
}
It really depends on your use case. If you need to do mappings between AnotherEntity and AnotherEntityDTO on other places, I would suggest to use a new interface so you can reuse it where you need it
Related
I am using spring data jpa in my spring boot project.
I am firing an JPQL query and using an projection to store the result of query.
My Projection :
public interface VeryBasicProjection {
String getTitle();
String getUrl();
}
My service calling this projection :
public List<VeryBasicDTO> getLatestData(int limit){
// Pageable for Limit
Pageable pageable = new PageRequest(0, limit);
// Get Data from DB
List<VeryBasicProjection> latestData = tableRepository.getLatestData("live", 2,pageable);
List<VeryBasicDTO> responseDTO = new ArrayList<>();
// Map Projection to DTO
for(VeryBasicProjection veryBasicProjection : latestData){
VeryBasicDTO veryBasicDTO = new VeryBasicDTO();
veryBasicDTO.buildDTO(veryBasicProjection);
responseDTO.add(veryBasicDTO);
}
return responseDTO;
}
Now I want to test this service using Mockito(Unit Test Case)
I am mocking the call to repository
using when and thenReturn.
My question is how do I mock the result of repository? What should be in thenReturn? I mean how do I create instance of projection and setData to it?
If you want to create an instance of your projection without creating a class implementing the interface, you can use SpelAwareProxyProjectionFactory.
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
// ...
ProjectionFactory factory = new SpelAwareProxyProjectionFactory();
VeryBasicProjection projection = factory.createProjection(VeryBasicProjection.class);
projection.setTitle("theTitle");
projection.setUrl("theUrl");
You also need to add setters in your projection:
public interface VeryBasicProjection {
String getTitle();
String getUrl();
void setTitle(String title);
void setUrl(String url);
}
Source: https://github.com/spring-projects/spring-data-examples/blob/master/rest/projections/src/test/java/example/springdata/rest/projections/SimpleProjectionTests.java
This is the simplest way to mock projections in TEST
VeryBasicProjection VeryBasicProjection = new VeryBasicProjection() {
String getTitle() {
return "Title";
}
String getUrl() {
return "url";
}
};
As an addition to Nis' answer:
If the interface doesn't have setters, the projection can be initialized with a map:
ProjectionFactory factory = new SpelAwareProxyProjectionFactory();
Map<String, String> map = Map.of(
"title", "theTitle",
"url", "theUrl"
);
VeryBasicProjection projection = factory.createProjection(VeryBasicProjection.class, map);
We have implemented the same stuff in below way
First mocked the two type of objects:
#Mock
private EntityManager em;
#Mock
private DemoProjectRepo demoProjectRepo;
My demoProjectRepo.findByAll returns List<DemoProjectDevices>
DemoProjectDevices device1 = new DemoProjectDevices();
device1.setAcctNbr("2365897412236589");
device1.setdeviceSeq(new BigDecimal(1));
device1.setCrteTms("2017-07-29 01:21:44.910807");
List<DemoProjectDevices> demoProjectDevices = new ArrayList<DemoProjectDevices>();
demoProjectDevices.add(device1);
For the mock when and thenReturn:
Mockito.when(demoProjectRepo.findByAll("2365897412236589", em))
.thenReturn(demoProjectDevices);
In your projection interface you need to add setters for the values you have getters for.
So when you have a concrete class implementing the projection interface you can add the values to that class so you might have something along these lines:
public interface VeryBasicProjection {
String getTitle();
String getUrl();
void setTitle(String title);
void setUrl(String url);
}
public class VeryBasicProjectionImpl implements VeryBasicProjection{
//add implementing methods
}
////
#Mock
Repository tableRepo;
#InjectMocks
ClassUnderTest c;
#Test
public void test(){
// Pageable for Limit
Pageable pageable = new PageRequest(0, limit);
VeryBasicProjection vbp = new VeryBasicProjectionImpl();
// add data to object here using the setters
List<VeryBasicProjection> projList = new ArrayList<>()
//add objects created
when(tableRepo.getLatestData("live", 2, pageable)).thenReturn(projList));
}
I have implemented Automapper in my MVC project but not sure if it is been done correctly. I am currently using Entity Framework Database First Approach and retrieving data using stored procedures. As you would be aware Entity Framework creates complex type object which is a wrapper around Stored Procedures.So I have created two classes for mapping purpose. One is used in the repository class to map the complex type to Entity class and second is the viewmodel that is used to map the entity class to view model in the controller. I havent explicitly mapped my entity class to viewmodel in the controller. So I am wondering how is the data bound to the grid as the grid is expecting viewmodel. I am looking forward for suggestions in terms of the approach that I have taken.
spGetUserProfileByUserProfileID_Result - Complex type object
UserProfile - Entity class.
UserProfileViewModel - ViewModel
AutoMapperConfiguration Class
public static void Configure()
{
Assembly[] assemblies = BuildManager.GetReferencedAssemblies().OfType<Assembly>().ToArray();
Mapper.Initialize(cfg =>
cfg.AddProfiles(AllClasses.FromAssemblies(assemblies)
.Where(
a =>
a.FullName.EndsWith("Mapping"))));
}
Mapping class
public class DomainToModelMapping : Profile
{
public DomainToModelMapping()
{
CreateMap<spGetUserProfileByUserProfileID_Result, UserProfile>().ReverseMap();
CreateMap<UserProfileViewModel, UserProfile>().ReverseMap();
}
}
Repository
public List<UserProfile> GetUserProfileById(int id)
{
if (MCRHelper.UserValidate() == 1)
{
var userProfiles = db.spGetUserProfileByUserProfileID(id);
return Mapper.Map<List<UserProfile>>(userProfiles);
}
else
{
return null;
}
}
Controller
public ActionResult UserProfile_Read([DataSourceRequest]DataSourceRequest request)
{
var response = mcrRepository.GetUserProfileById(0).ToDataSourceResult(request);
return Json(response, JsonRequestBehavior.AllowGet);
}
If I add the following , to my controller to map to viewmodel, I get an error Missing type map configuration or unsupported mapping.
Mapping types:
DataSourceResult -> UserProfile
Kendo.Mvc.UI.DataSourceResult -> CC.GRP.MCRequest.Models.UserProfile
var userProfile = mcrRepository.GetUserProfileById(0).ToDataSourceResult(request);
return Json(Mapper.Map<UserProfile>(userProfile), JsonRequestBehavior.AllowGet);
If your question is how to return the viewmodel instead of the entity model from your controller using Automapper, then use Automapper Queryable Extensions:
using Automapper.QueryableExtensions;
...
public JsonResult UserProfile_Read([DataSourceRequest]DataSourceRequest request)
{
var users = mcrRepository.GetUserProfileById(0).Project().To<UserProfileViewModel>();
var response = users.ToDataSourceResult(request);
return Json(response, JsonRequestBehavior.AllowGet);
}
Does it make sense to create another layer over the EF6 - Repository/UnitOfWork ?
In our custom repository we can add specific queries like GetTopXXX, GetLastUpdated, etc.
Bu we can do the same in Business Logic with LINQ on DBContext.
I would highly recommend to use a repository to separate the logic that retrieves the data in your situation.
Using the Repository pattern, very briefly, you will implement all your queries such as add, edit, update defined in your interface. And the way which you interact with the database is using Entity Framework.
public interface IProductRepository
{
void Add(Product product);
}
public class ProductRepository : IProductRepository
{
private readonly DbContenxt _dbContext;
public ProductRepository(DbContext dbContext)
{
_dbContext = dbContext;
}
public void Add(Product product)
{
var product = new Product() { Name = "Test" };
_dbContext.Add(product);
_dbContext.SaveChanges();
}
}
Let's say you have an order as an aggregate root. An order contains one or more line items.
It is my understanding that it's the repository's responsibility to instantiate an order object when asked.
The line items can be loaded at the time of the order object's creation (eager loaded), or the line item collection can be populated when it is accessed by the client code (lazy loaded).
If we are using eager loading, it's seems that the repository code would take responsibility with hydrating the line items when the order is created.
However if we are using lazy loading, how is the repository called when the LineItems collection is accessed without creating a dependency on the repository from the order domain class?
Main problem is in Repository's ability to get only aggregate roots (presenting aggregates), thus you cannot use Repository to get line items. This can lead to aggregate encapsulation violation.
I propose something like:
//Domain level:
public interface IOrderItemList {
IEnumerable<OrderItem> GetItems();
}
public class Order {
private IOrderItemList _orderItems;
public IEnumerable<OrderItem> OrderItems
{ get { return _orderItems.GetItems() } };
public Order(IOrderItemList orderItems)
{
_orderItems = orderItems;
}
}
public class OrderItemList : IOrderItemList
{
private IList<OrderItem> _orderItems;
public IEnumerable<OrderItem> GetItems() {
return _orderItems; //or another logic
}
//other implementation details
}
//Data level
public class OrderItemListProxy : IOrderItemList
{
//link to 'real' object
private OrderItemList _orderItemList;
private int _orderId;
//alternatively:
//private OrderEntity _orderEntity;
//ORM context
private DbContext _context;
public OrderItemListProxy(int orderId, DbContext context)
{
_orderId = orderId;
_context = context;
}
public IEnumerable<OrderItem> GetItems() {
if (_orderItemList == null)
{
var orderItemEntities = DbContext.Orders
.Single(order => order.Id == _orderId).OrderItems;
var orderItems = orderItemEntites.Select(...);
//alternatively: use factory to create OrderItem from OrderItemEntity
_orderItemList = new OrderItemList(orderItems);
}
return _orderItemList.GetItems();
}
}
public class OrderRepository
{
//ORM context
private DbContext _context;
Order GetOrder(int id)
{
var orderEntity = _context.Single(order => order.Id == id);
var order = new Order(new OrderItemListProxy(id, _context))
//alternatively:
//var order = new Order(new OrderItemListProxy(orderEntity, _context))
...
//init other fields
...
}
//other methods
...
}
Most important here is that IOrderItemList corresponds to domain layer, but OrderItemListProxy corresponds to data layer.
Finally,
You may use IList<OrderItem> instead of custom IOrderItemList or another appropriate interface.
Proxy implementation may differ.
I don't provide best practicies for using db context, it may depend on technologies you use.
I've requirement where I've to pass a parameter in the getter method(in my case another object). Wondering if thats possible and how can I achieve this? I'm implementing jaxws and this is my server side requirement. When client is created, getMetaValues(..) method is not available.
my code is
#XmlRootElement
#XmlAccessorType( XmlAccessType.PROPERTY)
public class Revision implements Serializable {
//other props and getter/setter
private List<Metavalue> metaValues;
#XmlElement
//Field is a custom class
public List<Metavalue> getMetaValues(Field field) {
metaValues=null;
if (field!=null) {
Map<String, Metakey> metadata = getMetadata();
Metakey metakey = metadata.get(field.getName());
if (metakey!=null) {
metaValues = metakey.getMetavalues();
}
}
return metaValues;
}
}
Thank you.
JAXB (JSR-222) implementations require a get method with no parameters. You could specify #XmlAccessorType(XmlAccessType.FIELD) so that JAXB deals directly with the field instead.