Given the following scenario:
A project using a framework
The framework defines basic entity classes (used for logging, user management etc.)
The project has application specific entity classes.
I want to subclass a framework class in a way that does not need changes to the framework code nor the framework specific database schema (apart from any constraints that maybe introduced by additional mappings).
Here is a simplified framework class:
package com.example.parent;
#Entity
#Table("entities")
public class ExampleEntity {
#Id
#GeneratedValue
protected Integer id;
protected String name;
}
And the application specific extension:
package com.example.child;
#Entity
public class ExampleEntity extends com.example.parent.ExampleEntity {
#OneToMany
#JoinColumn
protected Set<OtherEntity> otherEntities;
}
As you can see this just adds an additional mapping to an application specific entity class.
This won't work with Hibernate 4.3.11 out-of-the-box. It will try to create a discriminator column (dtype) which is not desired and IMHO not required here.
I want this to be as transparent as possible (i.e. without changing anything on the framework side) and without any additional manual mapping/casting in the application. Effectively, I want to trick Hibernate into loading only instances of com.example.child.ExampleEntity without the framework even noticing.
TL;DR
How to trick Hibernate into loading entities from the entities table as instances of com.example.child.ExampleEntity?
You can used #Inheritance(strategy = InheritanceType.JOINED) on the parent class. You can find an example here.
So it would work with
package com.example.parent;
#Entity
#Table("entities")
#Inheritance(strategy = InheritanceType.JOINED)
public class ExampleEntity {
#Id
#GeneratedValue
protected Integer id;
protected String name;
}
So you can join any other table to children or parent
This is the official documentation about inheritance mapping.
Related
With or without this annotation, there is a property on my JPA #Entity
#Entity
public class Myentity extends ResourceSupport implements Serializable {
...
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name="idrepository")
#JsonInclude(JsonInclude.Include.ALWAYS)
private MyentitySource entitysource;
...
}
that is not being mapped when I return:
#RequestMapping("/myentity/{uuid}")
public ResponseEntity<Myentity> getResourceById(#PathVariable("uuid") UUID uuid) {
Myentity result = myentityRepository.findOne(uuid);
return ResponseEntity.ok(myentityAssembler.toResource(result));
}
myentityAssembler.toResource(result) does contain this MyentitySource entitysource, but the JSON output does not.
The weirdest thing is I have another spring boot hateoas project where I am using the exact same entity, repository, controller, and assembler implementations, with the exact same dependencies and versions on my pom, and a very similar configuration (I am not defining any special jackson mappers or anything, just using the default rest/hateoas configuration), and it does work there: The MyentitySource entitysource property, which is another JPA entity extending ResourceSupport, gets serialized and included into the JSON output.
I have been a couple of hours at it already, but I am quite lost. I have verified this behavior is happening all through the application in both applications: #ManyToOne relations defined on any #Entity are being mapped and present in the JSON output on one application, but not in the other.
How can I get these fields to show up on the JSON output?
entitysource will be included if MyentitySource is not an exported entity. If it is one - what seems to be the case here - then it would be wrong to include it. Including associations could lead to sending the whole database to the client. Moreover it is a separate resource with its own URI. Consequently a link to that URI is included in the response.
CascadeType.ALL implies that Myentity is an aggregate, therefore MyentitySource should not be exported in the first place. That would solve your problem. If my assumption is wrong, then you can still use Projections to get entitysource included. I can refer you to this answer from Spring's Oliver Gierke and the relevant chapter of the documentation.
By default, in Spring Data Rest the #Id of the entity is not exposed. In line with the REST rules, we're supposed to use the URI of the resource to refer to it. Given this assumption, the findBy queries should work if you pass a URI to them, but they don't.
For example, say I have a one-to-many relationship between Teacher and Student. I want to find students by teacher.
List<Student> findByTeacher(Teacher teacher)
http://localhost:8080/repositories/students/search/findByTeacher?teacher=http://localhost:8080/repositories/teachers/1
This doesn't work because the framework is attempting to convert the teacher URI to a Long.
I get this error that says "Failed to convert from type java.lang.String to type java.lang.Long".
Am I missing something?
You could expose #Id s by configuring web intializer
//Web intializer
#Configuration
public static class RespositoryConfig extends
RepositoryRestMvcConfiguration {
#Override
protected void configureRepositoryRestConfiguration(
RepositoryRestConfiguration config) {
config.exposeIdsFor(Teacher.class);
}
}
Its good to change List to Page
List findByTeacher(Teacher teacher)
to
Page<Student> findByTeacher(#Param("teacher) Teacher teacher, Pageable pageable);
Also note #Param annotation is required along with Pageable. The latter is required because return type "Page"
3.Latest snapshots, not milestones work fine
See https://jira.spring.io/browse/DATAREST-502
Depending of your version of Spring Data, it would work as you want or not. If you are with Spring Data 2.4, you need to pass the URI. If you are with a previous version, you need to pass the id.
This is an Nhibernate question that has bothered me for some time...
If I model a simple order entry domain as:
public class Order: BaseEntity
{
public virtual Customer Customer {get; set;}
public Order(Customer customer)
{
...
}
}
public class Customer: BaseEntity
{
public virtual string Name {get; set;}
public virtual Order CreateOrder()
{
return new Order(this);
}
}
While the above code works to create an Order instance, the newly created instance will not be persisted to the DB unless either:
The BaseEntity or the derived class is aware of the NHibernate
session (which breaks POCO)
There is a service layer (or repository) that calls ISession.Save() on the
newly created Order object that needs to be NHibernate-aware
So, this leads me to believe that my NHibernate POCO classes themselves should not contain any of our business rules (and should be kept to only properties and constructors), but the service layer 'above' the domain model should be where the logic should live. Presumably, this service layer would receive its persistence functionality through dependency injection.
Anyone care to confirm/deny my assertion that business methods should NOT exist within the POCO model?
Thanks,
David
Business logic in the domain model is the whole point of having the model in the first place.
You can use Nhibernate's cascade feature to make your order become automatically persisted if the customer owning it is persistent.
Is there any way or design pattern can I use to get Generic CRUD operations?
Because I’m working on n-tire application using EF in the data layer and I don’t want to use CRUD Functions in Every Entities.
Your help would be appreciated
You can use the Repository pattern, where you implement the repository as an interface and then a base class. For instance:
IRepository where T : class
void Save(T entity )
T FindById( T id )
....
EntityFrameworkRepositoryBase : IRepository
void Save( T entity )
{
// do EF specfic stuff
}....
Then for a given entity you can create(or inject) a concrete repository:
PersonRepository : EntityFrameworkRepositoryBase
From there, simply call the PersonRepository to Save or Find Persons.
If i want to use Linq-SQL i also have to drag the DB Table unto the designer surface to create the entity classes.
I always like full control in my application and do not like the classes created by dotnet.
Is it possible to provide this connection between Linq and the DB using my own Data Access Layer Entity classes?
How can i get it done?
You can write your own classes very easily using Linq-to-SQL - just involves painting your classes with some Attributes.
For Example, this is a very simple table I have in one of my projects, and it works with Linq-to-SQL just fine:
[Table(Name = "Categories")]
public class Category : IDataErrorInfo
{
[Column(IsPrimaryKey = true, IsDbGenerated = true, AutoSync = AutoSync.OnInsert)]
public int Id { get; set; }
[Column] public string Name { get; set; }
[Column] public string ExtensionString { get; set; }
}
The code was very easy, especially if you make your property names line up with your table names (you don't have to).
Then you just need a Repository to connect to the DB:
class CategoryRepository : ICategoryRepository
{
private Table<Category> categoryTable;
public CategoryRepository(string connectionString)
{
categoryTable = (new DataContext(connectionString)).GetTable<Category>();
}
}
Of course there is more to it, but this shows you the very basics and it is not hard to do once you understand it. This way you have 100% control over your classes and you can still take advantage of Linq-to-SQL.
I learned this approach from Pro ASP.NET MVC Framework, an awesome book.
If you want to see more, all of my Linq-to-SQL classes were written from scratch on one of my projects you can browse here.
To avoid drag & drop you can take a look at SqlMetal.exe.
However, it sounds like you really are requesting Persistence Ignorance, and I'm not sure that this is possible with L2S - it certainly isn't possible with LINQ to Entities until .NET 4...
I once wrote a blog post on using SqlMetal.exe and subsequently modifying the generated schema - perhaps you will find it useful, although it has a different underlying motivation.
I've got a couple tutorials up on CodeProject that walk through how to do this, including how to handle the relationships (M:M, 1:M, M:1) in an OO way and keep them in synch as you make updates:
A LINQ Tutorial: Mapping Tables to Objects
A LINQ Tutorial: Adding/Updating/Deleting Data