While viewing Evans' project on sample DDD project, I notice that in the Cargo entity, Evans uses tracknumber which is an value object. Why he didn't chooses plain string tracknumber instead chooses value object for identity? Here is snippet from Evans:
public class Cargo implements Entity<Cargo> {
private TrackingId trackingId
}
public final class TrackingId implements ValueObject<TrackingId> {
private String id;
/**
* Constructor.
*
* #param id Id string.
*/
public TrackingId(final String id) {
Validate.notNull(id);
this.id = id;
}
A couple of things that would achieve:
Encapsulates the logic that the Tracking ID should not be null
Encapsulates the logic that the Tracking ID should not change once set.
With a plain string, the Cargo object would have to be aware of these rules. Using the Value Object approach means the TrackingId maintains these rules about itself.
Related
I often have to create sets of CRUD-like operations on web api:
CreateFoo()
GetFoo()
GetAllFoos()
CreateBar()
GetBar()
GetALlBars()
Often there is much overlap between an object used in create operation, and an object returned from get operation, for example:
Here is a toy example:
struct CreateEmployeeRequest {
string FirstName;
string LastName;
string EmployeeIdPattern; // the employee ID will be generated using this pattern.
}
and
struct PersonDto {
string FirstName;
string LastName;
int PersonId;
string Creator;
DateTime CreationDateTime;
string EmployeeId;
}
What are strategies available to me to avoid duplication here?
I can either have a single, partially initialized structure - essentially table-per-hierarchy approach, to use DB terminology; or put common fields into a PersonDtoBase and inherent both CreatePersonRequest and PersonDto objects from it.
I'm on C# 11 / .NET Core 7, if that matters.
I have a JSON value stored in SQL Server. I want to retrieve that JSON value and bind it to C# property (which is deserialized to desired entity). I want to know what would be the best practice to do that effectively? Right now, I'm doing like this:
Public class Employee
{
public int Id;
public string Name;
public int Age;
}
Public class EmployeeData
{
public string JsonEmployeeText {get;set;} // Binding the json string from database
public List<Employee> Employees { get { return JsonConvert.DeserializeObject<Employee>(JsonEmployeeText );}} //Converting the retrieved json string from Database to c# entity
}
I guess we should not do any sort of database logic on getters as it can sometimes delay the process of initialization in case we need to use this we need to make sure we enable the lazy loading
I have an application that gets a car entity from a third party database. I call the entity ThirdPartyCar. My application needs to create a Car entity by using data from a ThirdPartyCar. However, the Car entity must also derive some of its data from my application's database. For example, a status of a ThirdPartyCar might be _BOUGHT and through a database lookup my application must transform to Sold.
I currently have a Car constructor that has a ThirdPartyCar argument. But the Car constructor cannot populate the lookup data since it is an entity and entities should not have a reference to a repositories. So, I also have a service to populate the remaining data:
public class ThirdPartyCar {
#Id
private Long id;
private String vin;
private String status;
// more props + default constructor
}
public class Car {
#Id
private Long id;
private String vin;
private CarStatus status;
// more props (some different than ThirdPartyCar) + default constructor
public Car(ThirdPartyCar thirdPartyCar) {
this.vin = thirdPartyCar.getVin();
// more props set based on thirdPartyCar
// but props leveraging database not set here
}
public class CarStatus {
#Id
private Long id;
private String status;
}
public class CarBuilderService {
private final CarStatusMappingRepository repo;
public Car buildFrom(ThirdPartyCar thirdPartyCar) {
Car car = new Car(thirdPartyCar);
CarStatus status = repo.findByThirdPartyCarStatus(thirdPartyCar.getStatus());
car.setStatus(status);
// set other props (including nested props) that depend on repos
}
}
The logical place to create a Car based on a ThirdPartyCar seems to be the constructor. But I have a disjointed approach b/c of the need of a repo. What pattern can I apply such that all data is created in the constructor but still not have the entity be aware of repositories?
You should avoid linking two POJO classes from different domains in constructor. These two classes should not know anything about each other. Maybe they represent the same concept in two different systems but they are not the same.
Good approach is creating Abstract Factory interface which will be used everywhere where Car should be created from ThirdPartyCar:
interface ThirdPartyCarFactory {
Car createNewBasedOn(ThirdPartyCar source);
}
and one implementation could be your RepositoryThirdPartyCarFactory:
class RepositoryThirdPartyCarFactory implements ThirdPartyCarFactory {
private CarStatusMappingRepository repo;
private CarMapper carMapper;
public Car createNewBasedOn(ThirdPartyCar thirdPartyCar) {
Car car = new Car();
carMapper.map(thirdPartyCar, car);
CarStatus status = repo.findByThirdPartyCarStatus(thirdPartyCar.getStatus());
car.setStatus(status);
// set other props (including nested props) that depend on repos
return car;
}
}
In above implementation you can find CarMapper which knows how to map ThirdPartyCar to Car. To implement this mapper you can use Dozer, Orika, MapStruct or your custom implementation.
Other question is how you got ThirdPartyCar object. If you load it by ID from ThirdPartyRepository you can change your abstract factory to:
interface CarFactory {
Car createNew(String id);
}
and given implementation loads by ID ThirdPartyCar and maps it to Car. Everything is hidden by factory which you can easily exchanged.
See also:
Performance of Java Mapping Frameworks
I am creating a web application that needs a table of notifications to display to various users. For some reason the JPQL query I've written is throwing a java.lang.IllegalArgumentException. My application already has a transaction table, structured and queried using an identical approach (afaik), which works perfectly.
I have been shuffling the code around, changing variable names and character cases for hours trying to get this to work but I'm still getting the exception every time. Does anyone have any idea where I'm going wrong?
My NotificationEntity is as follows:
#Table(name="notificationentity")
#NamedQuery(name="fetch_user_notifications", query="SELECT n FROM NotificationEntity n WHERE n.notificationrecipient=:username")
#Entity
public class NotificationEntity implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotNull
String notificationSender;
#NotNull
String notificationrecipient;
... other fields + methods
}
The JPQL query is called from an EJB (NotificationStorageServiceBean) that implements an interface (NotificationStorageService) with the following method:
#Override
public synchronized List<NotificationEntity> getUserNotificationList(String username)
{
List notifications;
notifications = em.createNamedQuery("fetch_user_notifications").setParameter("notificationrecipient", username).getResultList();
return notifications;
}
And the EJB method is called from a CDI backing bean for my .xhtml UI, using the FacesContext's currently logged in user to provide the argument for these methods.
#EJB
NotificationStorageService notificationStore;
public List<NotificationEntity> getUserNotificationList()
{
return notificationStore.getUserNotificationList(this.currentUser);
}
The exact error I get is:
java.lang.IllegalArgumentException: You have attempted to set a parameter value using a name of notificationrecipient that does not exist in the query string SELECT n FROM NotificationEntity n WHERE n.notificationrecipient=:username.
The parameter name in a JPQL query starts with a colon. So just use
setParameter("username", username)
I have this code:
#Column(name = "foo")
#ReadTransformer(transformerClass=transformer.class)
private Date foo;
public static class transformer implements AttributeTransformer {
#Override
public void initialize(AbstractTransformationMapping atm) {
}
#Override
public Object buildAttributeValue(Record record, Object o, Session sn) {
}
}
My question is, how do I get the value to transform (from column foo) inside of buildAttributeVaule? It is not inside the record array.
You need one or more #WriteTransformer to write the fields you want selected (and thus get them selected), #Column is not used with a transformation mapping.
However, if you just have a single column, then just use a converter instead, #Convert,
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Mapping/Basic_Mappings/Default_Conversions_and_Converters
First check that the SQL generated is reading in the "foo" column by turning on logging. If it is, then check that the database is returning "foo" and not "FOO" - java is case sensitive on string looksups. It could be that "FOO" is in the record instead of "foo".