After converting to dto child set order jumbles up - mapstruct

After converting to dto using mapstruct, child id order jumbles up.
If i return just the entity without converting to dto the child is properly ordered
"data":[
{
"personName":"TestUser",
"cars":[
{
"id":"2021-000001"
},
{
"id":"2021-000003"
},
{
"id":"2021-000002"
},
{
"id":"2021-000004"
}
}
]

The reason why the order is different is due to the fact that MapStruct used a HashSet by default when mapping into a Set.
The current implementation types for MapStruct are the following:
Interface type
Implementation type
Iterable
ArrayList
Collection
ArrayList
List
ArrayList
Set
HashSet
SortedSet
TreeSet
NavigableSet
TreeSet
Map
HashMap
SortedMap
TreeMap
NavigableMap
TreeMap
ConcurrentMap
ConcurrentHashMap
ConcurrentNavigableMap
ConcurrentSkipListMap
This can be seen in Implementation types used for collection mappings
There is currently a feature request to change this into an order preserving set / map and it will be included in 1.5.
At the moment you can fix this by using an #ObjectFactory that will return a LinkedHashSet

Related

Is there a Deconstruct Mongo Response to DTO short cut?

If I have a table in a mongoDB with five properties and I only want to return four of them and none of the mongo added info such as v1 I can map the reposne to a dto like so,
const product = await this.productModel.findById(productId).exec()
return { id: product.id, title: product.title }
Is there a deconstruct shortcut for the return, to extract every field from an interface (Product) from the product response, to save typing each property out ? If for example im retunring 127 properties from a table of entires with 140.
interface Product {
id: string
title: string
...
}
Unfortunately no, typescript interfaces do not really exist when your program compiles
Interface is a structure that defines the contract in your application. It defines the syntax for classes to follow. Classes that are derived from an interface must follow the structure provided by their interface.
The TypeScript compiler does not convert interface to JavaScript. It
uses interface for type checking. This is also known as "duck typing"
or "structural subtyping".
So, you can't really read interface fields and then write some logic (you can maybe achieve this through reflection but it's a bad practice)
An alternative is to explicitly define what fields are to include/or exclude from your object
Suppose that I have an object with this interface:
interface Foo {
field1: string;
field2: string;
field3: string;
.....
field140: string;
}
What you can do here is to define what properties you want to exclude (you take the exclude approach here since you are returning 127 fields of 140)
// This isn't an implementation with mongoose (if you are using it),
// it's just to give you the idea
const FIELDS_TO_EXCLUDE = ["field128", "field129", "field130", ..., "field140"];
productModel.toDTO(){
const documentData = this;
FIELDS_TO_EXCLUDE.forEach(x => delete documentData[x]);
return documentData;
}
In this way, when you will execute the toDTO function your manipulate itself excluding (or including) the fields you want

How to disable sorting of return array?

I have a custom rest action like this (in a class that extends yii/rest/ActiveController):
public function actionTest()
{
return ["9" => "Nine", "1" => "one"];
}
When calling the API, the array output is in reverse order, ie:
{
"1": "One"
"9": "Nine",
}
I would like to have it in the original (expected) order...
Seems like the array was sorted somewhere after the array was returned in the action, but I can't figure out where. This only happens when the array key is an integer, an array like this is sorted as expected:
["id-9" => "Nine", "id-1" => "one"]
Have tried using an ArrayDataProvider setting 'sort' = false, but that made no difference.
Since you're exporting it as json and looking at that, from this question - Keeping dictionary keys of JSON Object in order in Objective C, the answer left by Henning Makholm says that:
In JSON objects, by definition, the order of the key-value pairs is not meaningful. The specification allows a JSON producer to permute them any way it want, even at random -- and does not require a parser to preserve the ordering. RFC 4627 says:
An object is an unordered collection of zero or more name/value pairs, where a name is a string and a value is a string, number, boolean, null, object, or array.
So json has no ordering, since it uses a dictionary as its data structure and typically dictionaries will have no implicit or explicit ordering due to the way they hash the keys for quick access.
It may be that the actual underlying representation in your program is ordered, but the json output has no such guarantee.
One way to fix this would be to move to a different data structure where order is preserved.

How to keep a groupedby list sorted in Play Framework 2 templates

I've got a list of complex objects that I want to display, grouped by one of its attribute in a Play 2 template.
I managed to do it :
#measures.groupBy(_.question.category).map {
case (category, items) => {
// Category stuff
#for(item <- items) {
// List of items
}
}
}
The problem is that the list was sorted in my Java controller, but the keyset of the map that I create is not sorted anymore (I would like to sort the key set using something like _.question.category.order).
Is there a way to have a sorted map on this attribute?
Thanks !
What type is measures? Did you try to use a LinkedHashSet? This should keep the elements order in contrast to e.g. a HashSet.

Entity Framework TPH - Additional WHERE clause only for one subtype

Suppose I have a class Parent, with two subclasses, AChild and BChild. I have these mapped to a single table using Entity Framework 5.0.0 on .NET 4.5, using TPH.
public abstract class Parent {
public string Type { get; set; } // Column with this name in DB is discriminator.
public string Status { get; set; }
}
public class AChild : Parent {
// Other stuff.
}
public class BChild : Parent {
// Other stuff.
}
The code to configure the mapping:
class ParentConfiguration : EntityTypeConfiguration<Parent> {
Map((EntityMappingConfiguration<AChild> mapping) => mapping
.Requires("Type")
.HasValue("A"));
Map((EntityMappingConfiguration<BChild> mapping) => mapping
.Requires("Type")
.HasValue("B"));
}
I have a need to run a query that returns both AChild and BChild objects. However, it needs to filter ONLY the AChild rows by a second column, which in this example I will call Status.
Ideally I would want to do the following:
public IList<Parent> RunQuery() {
IQueryable<Parent> query =
this.context.Set<Parent>()
.Where((Parent parent) => !parent.Type.Equals("A") || parent.Status.Equals("Foo"))
.OrderBy((Parent parent) => parent.Number);
return query.ToList();
}
This doesn't work. It insisted on looking for a "Type1" column instead of just letting both the discriminator and a "Type" property be mapped to the same "Type" column.
I know of the "OfType" extension method that can be used to completely filter down to one type, but that's too broad a brush in this case.
I could possibly run multiple queries and combine the results, but the actual system I'm building is doing paging, so if I need to pull back 10 rows, it gets messy (and inefficient) to query since I'll either end up pulling back too many rows, or not pull back enough and have to run extra queries.
Does anyone have any other thoughts?
There are few problems. First of all you cannot have discriminator mapped as a property. That is the reason why it is looking for Type1 column - your Type property results in second column because the first one is already mapped to .NET types of your classes. The only way to filter derived types is through OfType.
The query you want to build will be probably quite complex because you need to query for all Bs and concatenate them with result of query for filtered As. It will most probably not allow you to concatenate instances of Bs with As so you will have to convert them back to parent type.

EF4 inheritance and Stored procedures

I implemented inheritance with a discriminator field so all my records are in the same table. My basetype is Person (also the name of the table) and Driver and Passenger inherit from it. I receive instances of the correct type (Driver and Passenger) when I perform a query on the object context to Person. example:
var q = from d in ctx.Person
select d;
But I also create a function that calls a stored procedure and mapped the output of the function to the type Person. But now I get a list of Person and not Drivers or Passengers when I execute this method.
Anybody an idea how to solve this or is this a bug in EF4?
AFAIK, you can't use discriminator mapping (e.g TPH) when dealing with stored procedure mappings.
The stored procedure must be mapped to a complex type or custom entity (e.g POCO), the mapping cannot be conditional.
What you could do is map it to a regular POCO, but then project that result set into the relevant derived type (manual discrimination).
E.g:
public ICollection<Person> GetPeople()
{
var results = ExecuteFunction<Person>(); // result is ObjectResult<Person>
ICollection<Person> people = new List<Person>();
foreach (var result in results)
{
if (result.FieldWhichIsYourDiscriminator == discriminatorForDriver)
{
people.Add((Driver)result);
}
// other discriminators
}
}
If your always expecting a collection of one type (e.g only Drivers), then you wouldn't need the foreach loop, you could just add the range. The above is in case you are expecting a mixed bag of different people types.
Would be interested to see other answers, and if there is a better way though - but the above should work.