Generating the otherEntityField From Modelio using jhipster-uml on a one-to-many relationship - uml

I am trying to generate a Jhipster(2.27.0) application from Modelio(3.4.1) model with JHipster-UML(1.6.0).
On this example I have a one-to-many relationship between 2 entities (assessment and answer).
I want to generate the 'otherEntityField' allowing to browse the relation through text and not ID.
The only way I manage to do that was to setup a bidirectional one-to-many relationship like this:
Image one-to-many Modelio relationship
And after jhipster-uml generate the code, I have to change the generated entity "Assessment.java".
The #OneToMany annotation should use "assessment" mappedBy parameter and not "assessment(entity)".
Before changes:
#OneToMany(mappedBy = "assessment(entity)")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Answer> answers = new HashSet<>();
After changes:
#OneToMany(mappedBy = "assessment")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Answer> answers = new HashSet<>();
After that, it works.
Is this a bug from jhipster-uml or is there a way to generate directly the "otherEntityField" ?
In more concise question : How do you manage a bidirectional one-to-many relationship jhipster-uml generation with "otherEntityField" ?

This issue was a bug in jhipster-uml.
Issue:
https://github.com/jhipster/jhipster-uml/issues/132
Will be corrected in version 1.6.1.

Related

MikroORM: How to use 'insert_id' for subsequent persists?

How can I get the insert_id (or existing id on duplicate key error) from a persist? I'd like to use it in following persists before flush.
In my mind, even though the EntityManager doesn't have an id yet, it could still populate that and use it during flush, but I think my thinking is flawed here, I'm new to MikroORM. From what I can see in the docs, I can only achieve this using the Query Builder.
Thanks for your help!
You can just build the entity graph, the entity does not need to have a PK to be used in a relation:
const book = new Book(); // new entity, no PK
user.favorites.push(book); // doesnt matter if it has PK
await em.flush(); // if `user` was a managed entity, this will find the new book and save it to the database
console.log(book.id); // now we have the PK available on entity
In other words, the entity instance is what holds the identity, you use that, not the PK.

JHipster - Entity with JDL, Java entity class with unexpected #Column annotation

I tried creating a JHipster app with one of the options: --skip-client.
Also I disabled Liquibase afterwards.
Then I created a test entry, similar to:
entity Test {
id String,
hireDate ZonedDateTime
}
I put this into a test.jh file, executed on a terminal:
jhipster import-jdl test.jh
When I looked into the Java source of the app, I discovered a Test.java class, id was automatically recognized as a primary key I believe:
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
But hireDate was annotated with:
#Column(name = "hire_date")
private ZonedDateTime hireDate;
Why is that?
I created a view "Test" for this entity in my database, also the columns are "Id" and "HireDate".
But with the automaticaly added #Column annotation, the column name for example "hire_date" doesn't exist in my view.
Can I solve this somehow? I this something related to JHipster generator or to do with Spring Boot?
And there is another issue:
#Size(max = 100)
#Column(name = "jhi_type", length = 100)
private String type;
To name a Java field "type" seems ok, but JHipster makes "jhi_type" for #Column
Cheers
These are the JHipster naming conventions: snake-case for columns and camel-case for java entity fields. If you had used Liquibase, this would have worked fine.
You can't configure this behavior in the generator.
Disabling liquibase does not change the fact that you created a view in your database that does not respect JHipster naming conventions. JHipster generates code that expects columns to be named this way. Either you respect these conventions or you modify the generated code manually.
Alternatively, you could try jhispter-db-helper module but it seems this project has been abandoned.
No need to define the id field in the jdl, you get it for free by default.

How to use ObjectContext with Model Builder?

Is there a way we can use ObjectContext with DbContext's ModelBuilder? We don't want to use POCO because we have customized property code that does not modify entire object in update, but only update modified properties. Also we have lots of serialisation and auditing code that uses EntityObject.
Since poco does create a proxy with EntityObject, we want our classes to be derived from EntityObject. We don't want proxy. We also heavily use CreateSourceQuery. The only problem is EDMX file and its big connection string syntax web.config.
Is there any way I can get rid of EDMX file? It will be useful as we can dynamically compile new class based on reverse engineering database.
I would also like to use DbContext with EntityObject instead of poco.
Internal Logic
Access Modified Properties in Save Changes which is available in ObjectStateEntry and Save them onto Audit with Old and New Values
Most of times we need to only check for Any condition on Navigation Property for example
User.EmailAddresses.CreateSourceQuery()
.Any( x=> x.EmailAddress == givenAddress);
Access Property Attributes, such as XmlIgnore etc, we rely heavily on attributes defined on the properties.
A proxy for a POCO is a dynamically created class which derives from (inherits) a POCO. It adds functionality previously found in EntityObject, namely lazy loading and change tracking, as long as a POCO meets requirements. A POCO or its proxy does not contain an EntityObject as the question suggests, but rather a proxy contains functionality of EntityObject. You cannot (AFAIK) use ModelBuilder with EntityObject derivatives and you cannot get to an underlying EntityObject from a POCO or a proxy, since there isn't one as such.
I don't know what features of ObjectContext does your existing serialisation and auditing code use, but you can get to ObjectContext from a DbContext by casting a DbContext to a IObjectContextAdapter and accessing IObjectContextAdapter.ObjectContext property.
EDIT:
1. Access Modified Properties in Save Changes which is available in ObjectStateEntry and Save them onto Audit with Old and New Values
You can achieve this with POCOs by using DbContext.ChangeTracker. First you call DbContext.ChangeTracker.DetectChanges to detect the changes (if you use proxies this is not needed, but can't hurt) and then you use DbCotnext.Entries.Where(e => e.State != EntityState.Unchanged && e.State != EntityState.Detached) to get DbEntityEntry list of changed entities for auditing. Each DbEntityEntry has OriginalValues and CurrentValues and the actual Entity is in property Entity.
You also have access to ObjectStateEntry, see below.
2. Most of times we need to only check for Any condition on Navigation Property for example:
User.EmailAddresses.CreateSourceQuery().Any( x=> x.EmailAddress == givenAddress);
You can use CreateSourceQuery() with DbContext by utilizing IObjectContextAdapter as described previously. When you have ObjectContext you can get to the source query for a related end like this:
public static class DbContextUtils
{
public static ObjectQuery<TMember> CreateSourceQuery<TEntity, TMember>(this IObjectContextAdapter adapter, TEntity entity, Expression<Func<TEntity, ICollection<TMember>>> memberSelector) where TMember : class
{
var objectStateManager = adapter.ObjectContext.ObjectStateManager;
var objectStateEntry = objectStateManager.GetObjectStateEntry(entity);
var relationshipManager = objectStateManager.GetRelationshipManager(entity);
var entityType = (EntityType)objectStateEntry.EntitySet.ElementType;
var navigationProperty = entityType.NavigationProperties[(memberSelector.Body as MemberExpression).Member.Name];
var relatedEnd = relationshipManager.GetRelatedEnd(navigationProperty.RelationshipType.FullName, navigationProperty.ToEndMember.Name);
return ((EntityCollection<TMember>)relatedEnd).CreateSourceQuery();
}
}
This method uses no dynamic code and is strongly typed since it uses expressions. You use it like this:
myDbContext.CreateSourceQuery(invoice, i => i.details);

What do we call for these types of objects that used within Domain Model in DDD?

I have tried to find a solution to this naming problem, but I could not find a similar usage anywhere on the web. It could be either we have a design flow in the domain model, or we simply don't use the appropriate name for so called "ValueObjects".
Please read below..
We use Domain Driven Design with CQRS pattern. Below is how the domain model has been designed.
P.S Not related but for your information, our application uses ASP.NET MVC and the Controller comminicate withe the Service Layer. DTOs (Data Transfer Objects) are passed in/out to the MVC Controllers, which is not in the above diagram.
The problem is that we don’t use the "ValueObject" correctly. According Martin Fowler’s definition our ValueObjects are not a true representation of a ValueObject.
http://martinfowler.com/bliki/ValueObject.html
For example our ValueObjects have an identity.
public class NoteValue
{
public int Id { get; set; }
public string NoteName { get; set; }
public string NoteNumber { get; set; }
public DateTime NotExpiry { get; set; }
}
These ValueObjects simply carry data between the Commands, AggregateRoots and Domain Entities.
For example AggregateRoot simply creates ValueObjects based on the Domain Entities, and return those ValueObjects to the Command Layer.
Below is not the complete implementation. Just a simple example to show the interaction
AggregateRoot extension method:
private static IList<NoteValue> ToValueObject(this ICollection<Note> source)
{
var values = new List<NoteValue>();
if (source != null)
source.ForEach(i => values.Add(i.ToValueObject()));
return values;
}
AggregateRoot :
Public IList<NoteValue> GetNotesValues()
{
return this._notes.ToValueObject();
}
Command :
var motesValues = notesAggregate.GetNotesValues();
We are struggling to find an appropriate name for these so called “ValueObjets”. They don't seem to be DTOs either and also we want to be able to differentiate from the DTOs that are used in the Services layer. Specifically we want to know an appropriate name that we can call for these types of objects (ValueObjects). Any thoughts greatly appreciated.
I don't know if this answers your questions but I might hopefully point you in the right direction.
There is a very good talk about Value Objects by Dan Berg Johnsson: http://www.viddler.com/v/6939b23
Also have a look at Vaughn Vernon's papers on Effective Aggregate Design: http://dddcommunity.org/library/vernon_2011
All in all DDD (especially when applying CQRS on the architectural level) takes some time to grasp. Be patient, read, learn, and join the DDD/Cqrs Google group

DDD: keep a link to an entity inside an aggregate root, for reporting only

I'm refactoring a project using DDD, but am concerned about not making too many Entities their own Aggregate Root.
I have a Store, which has a list of ProductOptions and a list of Products. A ProductOption can be used by several Products. These entities seem to fit the Store aggregate pretty well.
Then I have an Order, which transiently uses a Product to build its OrderLines:
class Order {
// ...
public function addOrderLine(Product $product, $quantity) {
$orderLine = new OrderLine($product, $quantity);
$this->orderLines->add($orderLine);
}
}
class OrderLine {
// ...
public function __construct(Product $product, $quantity) {
$this->productName = $product->getName();
$this->basePrice = $product->getPrice();
$this->quantity = $quantity;
}
}
Looks like for now, DDD rules as respected. But I'd like to add a requirement, that might break the rules of the aggregate: the Store owner will sometimes need to check statistics about the Orders which included a particular Product.
That means that basically, we would need to keep a reference to the Product in the OrderLine, but this would never be used by any method inside the entity. We would only use this information for reporting purposes, when querying the database; thus it would not be possible to "break" anything inside the Store aggregate because of this internal reference:
class OrderLine {
// ...
public function __construct(Product $product, $quantity) {
$this->productName = $product->getName();
$this->basePrice = $product->getPrice();
$this->quantity = $quantity;
// store this information, but don't use it in any method
$this->product = $product;
}
}
Does this simple requirement dictates that Product becomes an aggregate root? That would also cascade to the ProductOption becoming an aggregate root, as Product has a reference to it, thus resulting in two aggregates which have no meaning outside a Store, and will not need any Repository; looks weird to me.
Any comment is welcome!
Even though it is for 'reporting only' there is still a business / domain meaning there. I think that your design is good. Although I would not handle the new requirement by storing OrderLine -> Product reference. I would do something similar to what you already doing with product name and price. You just need to store some sort of product identifier (SKU?) in the order line. This identifier/SKU can later be used in a query. SKU can be a combination of Store and Product natural keys:
class Sku {
private String _storeNumber;
private String _someProductIdUniqueWithinStore;
}
class OrderLine {
private Money _price;
private int _quantity;
private String _productName;
private Sku _productSku;
}
This way you don't violate any aggregate rules and the product and stores can be safely deleted without affecting existing or archived orders. And you can still have your 'Orders with ProductX from StoreY'.
Update: Regarding your concern about foreign key. In my opinion foreign key is just a mechanism that enforces long-living Domain relationships at the database level. Since you don't have a domain relationship you don't need the enforcement mechanism as well.
In this case you need the information for reporting which has nothing to do with the aggregate root.
So the most suitable place for it would be a service (could be a domain service if it is related to business or better to application service like querying service which query the required data and return them as DTOs customizable for presentation or consumer.
I suggest you create a statistics services which query the required data using read only repositories (or preferable Finders) which returns DTOs instead of corrupting the domain with query models.
Check this

Resources