I'd like to add a derived list to a DTO/model object when mapping from an entity. For example, I have an entity class named Company that has a list of Employees. I'd like for the Company Model object to contain the list of Employees as well as a list of Employees who are Managers. (This is not my actual class names, but this type of thing is what I'm trying to do). So, I want the Company DTO to have a list of Employees and a list of Managers where the Managers is a subset of Employees that is derived by filtering the list of Employees.
I tried using a mapping expression and a default method. However, I need to use the EmployeeMapper and it seems that I don't have access to the mapper.
Here's what I tried...
#Mapper(componentModel = "spring", uses = {EmployeeMapper.class})
public interface CompanyMapper extends IEntityMapper<CompanyModel, Entity> {
#Mapping(expression = "java(deriveManagers(model))", target = "managers")
EntityModel toModel(Company company);
default List<EmployeeModel> deriveManagers(Company company) {
List<EmployeeModel> managers = new ArrayList<EmployeeModel>();
company.getEmployees().forEach(nextEmployee -> {
if (nextEmployee.getJobTitle().equals(JobTitle.MANAGER)) {
managers.add(this.EmployeeMapper.toModel(nextEmployee);
}
});
return managers;
}
}
I decided to do this processing in the DTO/Model object rather than in the Mapper. The list can be derived as a subset of the EmployeeModel objects in the CompanyModel object. Therefore, I think that this is the right place to derive this list. It is not really a mapping from Entity to Model object as much as it is a derived attribute in the Model object.
Related
I want to create a list of complex DTO objects with data from several Entities and one non-Entity-parameter. Let's say my DTO class has constructor:
public MyDto(String entityField, String someString) {...}
and I would like to use the CriteriaBuilder.construct method to create my list by doing like this:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<MyDto> query = builder.createQuery(MyDto.class);
Root<MyEntity> root = query.from(MyEntity.class);
builder.construct(MyDto.class, root.get("entityField"), someString);
...
but I am not allowed to do it, because the construct method wants from me only javax.persistence.criteria.Selection arguments.
The question: is there is a way to do it similar to this (at one blow) with Criteria API? Or I need to load MyEntity objects first and go through them and create a list of DTOs (not so pretty)?
I use this approach each time I've a projection that collect fields from different entities or for privacy reason i must not return some data (for example passwords)
query.select(
builder.construct(
MyDto.class,
root.get("myfield"), // for field
cb.literal(1), // for number
cb.literal("blah blah") // for string
));
I have a GridView which needs to page and sort data which comes from a collection of Customer objects.
Unfortunately my customer information is stored separately...the customer information is stored as a Customer ID in my database, and the Customer Name in a separate DLL.
I retrieve the ID from the database using Entity Framework, and the name from the external DLL through a partial class.
I am getting the ID from my database as follows:
public class DAL
{
public IEnumberable<Customer> GetCustomers()
{
Entities entities = new Entities();
var customers = (from c in entities.Customers
select c);
//CustomerID is a field in the Customer table
return customers;
}
}
I have then created a partial class, which retrieves the data from the DLL:
public partial class Customer
{
private string name;
public string Name
{
if (name==null)
{
DLLManager manager = new DLLManager();
name= manager.GetName(CustomerID);
}
return name;
}
}
In my business layer I can then call something like:
public class BLL
{
public List<Customer> GetCustomers()
{
DAL customersDAL = new DAL();
var customers = customersDAL.GetCustomers();
return customers.ToList();
}
}
...and this gives me a collection of Customers with ID and Name.
My problem is that I wish to page and sort by Customer Name, which as we have seen, is populated from a DLL. This means I cannot page and sort in the database, which is my preferred solution. I am therefore assuming I am going to have to call of the database records into memory, and perform paging and sorting at this level.
My question is - what is the best way to page and sort an in-memory collection. Can I do this with my List in the BLL above? I assume the List would then need to be stored in Session.
I am interested in people's thoughts on the best way to page and sort a field that does not come from the database in an Entity Framework scenario.
Very grateful for any help!
Mart
p.s. This question is a development of this post here:
GridView sorting and paging Entity Framework with calculated field
The only difference here is that I am now using a partial class, and hopefully this post is a little clearer.
Yes, you can page and sort within you list in the BLL. As long as its fast enough I wouldn't care to much about caching something in the session. An other way would be to extend your database with the data from you DLL.
I posted this question slightly differently on a different forum, and got the following solution.
Basically I return the data as an IQueryable from the DAL which has already been forced to execute using ToList(). This means that I am running my sorting and paging against an object which consists of data from the DB and DLL. This also allows Scott's dynamic sorting to take place.
The BLL then performs OrderBy(), Skip() and Take() on the returned IQueryable and then returns this as a List to my GridView.
It works fine, but I am slightly bemused that we are perfoming IQueryable to List to IQueryable to List again.
1) Get the results from the database as an IQueryable:
public class DAL
{
public IQueryable<Customer> GetCustomers()
{
Entities entities = new Entities();
var customers = (from c in entities.Customers
select c);
//CustomerID is a field in the Customer table
return customers.ToList().AsQueryable();
}
}
2) Pull the results into my business layer:
public class BLL
{
public List<Customer> GetCustomers(intint startRowIndex, int maximumRows, string sortParameter)
{
DAL customersDAL = new DAL();
return customersDAL.GetCustomers().OrderBy(sortParameter).Skip(startRowIndex).Take(maximumRows).ToList();
}
}
Here is the link to the other thread.
http://forums.asp.net/p/1976270/5655727.aspx?Paging+and+sorting+Entity+Framework+on+a+field+from+Partial+Class
Hope this helps others!
I have an object like so:
public class Intent
{
public List<Entity> Updates { get; set; }
}
Which I wish to serialize into XML for passing as a message using MSMQ. The list of type Entity can contain any number of instances of classes that inherit from Entity. For example, there may be:
public Person : Entity { /* ... */ }
public Vehicle : Entity { /* ... */ }
I'm using XmlMessageFormatter, which so far I have defined as:
XmlMessageFormatter _formatter =
new XmlMessageFormatter(new[] { typeof(T) });
Where T in this instance is Intent (as above).
Trouble is, when the code actually attempts to serialize the following exception occurs:
The type CoreApi.Domain.Person was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
I believe this is because I need to tell the serializer somehow of the fact that Person is a child class of entity.
I've seen solutions that basically entail adorning Entity with multiple XmlInclude decorations, which in my scenario is unworkable as the list of inheritors of Entity is large and could grow - I don't want to constantly update this list as new inheritors are added.
I've seen other solutions that use XmlSerializer, passing in a list of known types, the trouble with this is that I somehow need to replace XmlMessageSerialiser with the XmlSerialiser instance which isn't compatible.
I have a domain object which has a collection of primitive values, which represent the primary keys of another domain object ("Person").
I have a Wicket component that takes IModel<List<Person>>, and allows you to view, remove, and add Persons to the list.
I would like to write a wrapper which implements IModel<List<Person>>, but which is backed by a PropertyModel<List<Long>> from the original domain object.
View-only is easy (Scala syntax for brevity):
class PersonModel(wrappedModel: IModel[List[Long]]) extends LoadableDetachableModel[List[Person]] {
#SpringBean dao: PersonDao =_
def load: List[Person] = {
// Returns a collection of Persons for each id
wrappedModel.getObject().map { id: Long =>
dao.getPerson(id)
}
}
}
But how might I write this to allow for adding and removing from the original List of Longs?
Or is a Model not the best place to do this translation?
Thanks!
You can do something like this:
class PersonModel extends Model<List<Person>> {
private transient List<Person> cache;
private IModel<List<String>> idModel;
public PersonModel( IModel<List<String>> idModel ) {
this.idModel = idModel;
}
public List<Person> getObject() {
if ( cache == null ) {
cache = convertIdsToPersons( idModel.getObject() );
return cache;
}
public void setObject( List<Person> ob ) {
cache = null;
idModel.setObject( convertPersonsToIds( ob ) );
}
}
This isn't very good code but it shows the general idea. One thing you need to consider is how this whole thing will be serialised between requests, you might be better off extending LoadableDetachableModel instead.
Another thing is the cache: it's there to avoid having to convert the list every time getObject() is called within a request. You may or may not need it in practice (depends on a lot of factors, including the speed of the conversion), but if you use it, it means that if something else is modifying the underlying collection, the changes may not be picked up by this model.
I'm not quite sure I understand your question and I don't understand the syntax of Scala.
But, to remove an entity from a list, you can provide a link that simply removes it using your dao. You must be using a repeater to populate your Person list so each repeater entry will have its own Model which can be passed to the deletion link.
Take a look at this Wicket example that uses a link with a repeater to select a contact. You just need to adapt it to delete your Person instead of selecting it.
As for modifying the original list of Longs, you can use the ListView.removeLink() method to get a link component that removes an entry from the backing list.
I have an object that has been populated with the contents of four different related entities. However i have another entity in which i cannot include as part of the query due to it not being related in the navigation properites directly to the IQueryable table i am pulling. The entity i am trying to include is related to one of the four different entities that have been included successfully.
Is there a way to include(during db hit or afterwards) this entity as part of the overall object i am creating?
Here is an example of what my calls look like to build the CARTITEM object:
public List<CARTITEM> ListCartItem(Guid cartId)
{
//Create the Entity object
List<CARTITEM> itemInfo = null;
using (Entities webStoreContext = new Entities())
{
//Invoke the query
itemInfo = WebStoreDelegates.selectCartItems.Invoke(webStoreContext).ByCartID(cartId).ToList();
}
//Return the result set
return itemInfo;
}
here is the selectCartItems filter(Where i would normally do the includes):
public static Func<Entities, IQueryable<CARTITEM>> selectCartItems =
CompiledQuery.Compile<Entities, IQueryable<CARTITEM>>(
(cart) => from c in cart.CARTITEM.Include("ITEM").Include("SHIPPINGOPTION").Include("RELATEDITEM").Include("PROMOTION")
select c);
from this i have my CARTITEM object. Problem is i want to include the PROMOTIONTYPE table in this object, but since the CARTIEM entity doesn't have a navigation property directly to the PROMOTIONTYPE table i get an error.
Let me know if you need any more clarification.
Thanks,
Billy
You can use join and if it is the same database and server it should generate the join in SQL and do it all in one call...
LinqToEnties join example