Spring Data Envers custom metadata - spring-data

I have marked my entity #Audited and I can see that it logs the revision number and timestamp of a new revision, but how can I add custom metadata? I believe it must be possible since org.springframework.data.RevisionMetadata has the getDelegate() method with the following Javadoc:
Returns the underlying revision metadata which might provider more detailed implementation specific information.

From a pure Hibernate Envers perspective, if you want your revision entity to store additional context information about a revision such as who modified the entities or perhaps a reason for the change, then you would want to do this through a RevisionListener callback combined with a custom extension to DefaultRevisionEntity.
For example:
#Entity
#RevisionEntity(CustomRevisionListener.class)
public class CustomRevisionEntity extends DefaultRevisionEntity {
private String userName;
/* getter/setters */
}
public class CustomRevisionListener implements RevisionListener {
#Override
public void newRevision(Object revisionEntity) {
CustomRevisionEntity cre = (CustomRevisionEntity)revisionEntity;
cre.setUserName( UserContextHolder.getUserContext().getUserName() );
}
}
Envers will detect the special annotated #RevisionEntity entity-class and use it. It will also detect the specified RevisionListener implementation and will instantiate and callback to this class when a new revision entity is constructed.
Unfortunately, I can't speak for how this translates usage-wise with respect towardspring-data and spring-data-envers projects.

Related

Disable query creation from method name - use of projections

I would like to use the Spring Data Projection technique in order to extract from a table only some fields (and not all fields of the table).
As described in the documentation (https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections) I created a simple interface, for example:
interface NamesOnly {
String getFirstname();
String getLastname();
}
But I have some problems to use it.
Problem 1:
First of all, I would like to use the name findAll() to create a query that finds all rows with only two fields (firstName and lastName):
#Repository
public interface PersonaRepository extends JpaRepository<Persona, Long> {
List<NamesOnly> findAll();
}
But in this case I have these errors (maybe because findAll() is a method of the JpaRepository):
implements org.springframework.data.jpa.repository.JpaRepository.findAll
The return type is incompatible with JpaRepository.findAll()
Problem 2:
Ok, so I try to change the name of the method to findAllOnlyNames():
#Repository
public interface PersonaRepository extends JpaRepository<Persona, Long> {
List<NamesOnly> findAllOnlyNames();
}
But now I have this error:
Caused by:
org.springframework.data.mapping.PropertyReferenceException: No
property findAllOnlyNames found for type Persona!
Because Spring tries to create a query from the name.
1) Could it be possible to reuse the method name findAll() without having problems with JpaRepository?
2) Could it be possible to turn off the query creation from the method name (only for some queries, not for all projects or repositories)?
You are on the right track, your findAll() is in conflict with the ones specified on the existing Spring Data interfaces and you can rename it (as you tried) but it still has to be a name that is compatible with the query derivation mechanism. Try this instead:
#Repository
public interface PersonaRepository extends JpaRepository<Persona, Long> {
List<NamesOnly> findAllOnlyNamesBy();
}
This part of the Spring Data JPA documentation explains how the query creation process works:
The mechanism strips the prefixes find…By, read…By, query…By, count…By, and get…By from the method and starts parsing the rest of it.
So you just need to add the By keyword in the method name, anything after that keyword is treated as a condition, in this case there is no condition so it fetches everything.
To disable the query derivation from the method name you would need to add an #Query(...) annotation to the method and specify either a JPA or native query instead.
You can specify an explicit query rather than rely on it being derived from the method name.
#Repository
public interface PersonaRepository extends JpaRepository<Persona, Long> {
#Query("select p from Persona p")
List<NamesOnly> findAllOnlyNames();
}
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query
Overriding findAll() (even in the unlikely event it is possible) is probably a bad idea.

How do I implement DbContext inheritance for multiple databases in EF7 / .NET Core

I am building web APIs in ASP.NET Core 1.1.
I have a number different databases (for different systems) which have common base schemas for configuration items such as Configuration, Users and groups (about 25 tables in all). I am trying to avoid duplicating the quite extensive EF configuration for the shared part of the model by inheriting from a base class as shown in the diagram.
However, this does not work because of the Entity Framework (EF) requirement to pass DbContextOptions<DerivedRepository> as a parameter to the constructor, where DerivedRepository must match the type of the repository the constructor is called on. The parameter must then be passed down to the base DbContext by calling :base(param).
So when (for example) InvestContext is initialised with DbContextOptions<InvestContext>, it calls base(DbContextOptions<InvestContext>) and EF throws an error because the call to the ConfigurationContext constructor is receiving a parameter of type DbContextOptions<InvestContext> instead of the required type DbContextOptions<ConfigurationContext>. Since the options field on DbContext is defined as
private readonly DbContextOptions _options;
I can't see a way around this.
What is the best way to define the shared model once and use it multiple times? I guess I could create a helper function and call it from every derived context, but it's not nearly as clean or transparent as inheritance.
I would like to bring this post from the OP's GitHub issue to everyone's attention:
I was able to resolve this without a hack by providing a protected constructor that uses DbContextOptions without any type. Making the second constructor protected ensures that it will not get used by DI.
public class MainDbContext : DbContext {
public MainDbContext(DbContextOptions<MainDbContext> options)
: base(options) {
}
protected MainDbContext(DbContextOptions options)
: base(options) {
}
}
public class SubDbContext : MainDbContext {
public SubDbContext (DbContextOptions<SubDbContext> options)
: base(options) {
}
}
OK, I have got this working in a way which still uses the inheritance hierarchy, like this (using InvestContext from above as the example):
As stated, the InvestContext class receives a constructor parameter of type DbContextOptions<InvestContext>, but must pass DbContextOptions<ConfigurationContext> to it's base.
I have written a method which digs the connectionstring out of a DbContextOptions variable, and builds a DbContextOptions instance of the required type. InvestContext uses this method to convert its options parameter to the right type before calling base().
The conversion method looks like this:
protected static DbContextOptions<T> ChangeOptionsType<T>(DbContextOptions options) where T:DbContext
{
var sqlExt = options.Extensions.FirstOrDefault(e => e is SqlServerOptionsExtension);
if (sqlExt == null)
throw (new Exception("Failed to retrieve SQL connection string for base Context"));
return new DbContextOptionsBuilder<T>()
.UseSqlServer(((SqlServerOptionsExtension)sqlExt).ConnectionString)
.Options;
}
and the InvestContext constructor call changes from this:
public InvestContext(DbContextOptions<InvestContext> options):base(options)
to this:
public InvestContext(DbContextOptions<InvestContext> options):base(ChangeOptionsType<ConfigurationContext>(options))
So far both InvestContext and ConfigurationContext work for simple queries, but it seems like a bit of a hack and possibly not something the designers of EF7 had in mind.
I am still concerned that EF is going to get itself in a knot when I try complex queries, updates etc. It appears that this is not a problem, see below)
Edit: I've logged this problem as an issue with the EF7 team here, and a team member has suggested a change to the EF Core core as follows:
"We should update the check to allow TContext to be a type that is derived from the current context type"
This would solve the problem.
After further interaction with that team member (which you can see on the issue) and some digging through the EF Core code, the approach I've outlined above looks safe and the best approach until the suggested change is implemented.
Depending on your requirements you can simply use the non type specific version of DbContextOptions.
Change these:
public ConfigurationContext(DbContextOptions<ConfigurationContext> options):base(options)
public InvestContext(DbContextOptions<InvestContext> options):base(options)
to this:
public ConfigurationContext(DbContextOptions options):base(options)
public InvestContext(DbContextOptions options):base(options)
Then if you create your ConfigurationContext first, the classes that inherit it seem to get the same configuration. It may also depend on the order in which you initialize the different contexts.
Edit:
My working example:
public class QueryContext : DbContext
{
public QueryContext(DbContextOptions options): base(options)
{
}
}
public class CommandContext : QueryContext
{
public CommandContext(DbContextOptions options): base(options)
{
}
}
And in Startup.cs
services.AddDbContext<CommandContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddDbContext<QueryContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
alternatively, in a test class:
var connectionString = "Data Source=MyDatabase;Initial Catalog=MyData;Integrated Security=SSPI;";
var serviceProvider = new ServiceCollection()
.AddDbContext<QueryContext>(options => options.UseSqlServer(connectionString))
.BuildServiceProvider();
_db = serviceProvider.GetService<QueryContext>();

JavaEE app structure

I'm creating a web app using JEE7. My question is about the architecture of my application. Basically, I have several entity classes (business class) that represent what will be stored in my database. For example I've got an entity class Book and an entity class Comic.
To access the database I want to create an EJB (kindda like the DAO design pattern). And here is my problem, I couldn't find a precise answer online.
Should I create one #remote interface and one #stateless class with all the methods to add/delete/get/update for both the Book class and the comic class ?
Or should I create 2 #remote interfaces and 2 #stateless classes (2 EJB), one for each entity class ?
Because lets imagine I create a bigger web app. If I have 100 entity classes, with the first method I'll have one huge EJB but with the second I'll have 100 EJB with their interfaces. I think the second is better but I'm not sure. What do you think ?
Why not just use one stateless bean and one remote interface?
A very nice feature of remote beans is, that they can be generic, so basically at minimum you only need one interface and one remote bean at all (see SimpleEntity and its remote bean).
I use a mix of a very generic remote bean DAO to read simple entities and some specific beans for entities which need more logic on CUD operations. Following i just extracted the minimum interfaces to reproduce it.
If i create a new table and entity it can immediately be used at the remote client.
Entities
/*
* Complex entity with enhanced CRUD logic
*/
public class Foo implements Entity { }
/*
* Simple entity without complex CRUD logic
*/
public class Bar implements SimpleEntity { }
Interface
public interface Entity { }
public interface SimpleEntity extends Entity { }
/*
* Generic entity DAO interface, for remote beans and other datasources
*/
public interface IEntityDAO<T extends Entity>
{
public T get(Class<T> type, long id);
public T update(T t);
}
/*
* Generic remote bean interface for a JNDI service locator lookup
*/
public interface EntityDAOBeanRemote<T extends Entity> extends IEntityDAO<T> { }
Stateless remote Beans
/*
* 'abstract' base class for stateless DAO beans
*/
public class AEntityDAOBean<T extends Entity> implements EntityDAOBeanRemote<T>
{
public T get(Class<T> type, long id)
{
Session session = // obtain current hibernate session
return id == (T) session.createCriteria(type).add(Restrictions.idEq(id)).uniqueResult();
}
public T update(T t, long id)
{
Session session = // obtain current hibernate session
session.update(t);
return t; // return updated instance
}
}
/*
* Generic stateless remote DAO bean implementation
*/
#Stateless(mappedName = "SimpleEntityDAOBean")
#Remote(EntityDAOBeanRemote.class)
public class SimpleEntityDAOBean extends AEntityDAOBean<SimpleEntity> implements EntityDAOBeanRemote<SimpleEntity>
{
// empty since all methods are from parent class
}
/*
* Foo specific remote DAO bean
*/
#Stateless(mappedName = "FooDAOBean")
#Remote(EntityDAOBeanRemote.class)
public class FooDAOBean extends AEntityDAOBean<SimpleEntity> implements EntityDAOBeanRemote<Foo>
{
#Override
public Foo update(Foo foo)
{
// make specific foo things and update
return foo;
}
}
Client
Using JNDI at your client you can call the bean using a JNDI service locator pattern like:
EntityDAOBeanRemote<Foo> fooDAOBeanRemote = jndiServiceLocator
.getEntityDAOBeanRemote(Foo.class);
EntityDAOBeanRemote<Bar> barDAOBeanRemote = jndiServiceLocator
.getEntityDAOBeanRemote(Bar.class);
Client JSF
With generic JSF converters and a generic extension of a DAO for a GUI framework (such as PrimeFaces LazyDataModel) it saves a lot of time making new entities quickly accessible in JSF beans and editable in the GUI.
Java EE application architecture is obviously a massive topic, but a common approach would be to create a Session EJB to expose general API calls to your client and then use a coarse grain Entity EJB to handle your persistent data. These Entity EJBs can manage a number of finer grained Java objects and classes that map onto your database structure.
This might be a good place to start:
https://docs.oracle.com/cd/A87860_01/doc/java.817/a83725/entity1.htm

Using Entity Framework along with Dapper

I need guidance on designing data layer for my Web API services. The Web API controllers call the service layer which calls the data layer.
I am planning to use Entity Framework along with Dapper. It might not be a good solution to use both of them together, but I need both. I need EF as it is easier to use and developers in my team are familiar. I need Dapper for performance. So, it will be a mix depending on where the dapper can make significant impact and where we can compromise on being a little late.
When using EF, I wanted to use unit of work with repository for each entity. My repository will be like
public class StudentRepository : IStudentRepository, IDisposable
{
private SchoolContext context;
public StudentRepository(SchoolContext context)
{
this.context = context;
}
public IEnumerable<Student> GetStudents()
{
return context.Students.ToList();
}
}
I took that sample code from http://www.asp.net/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
So, now I wanted to introduce Dapper.
Approach 1: Initially I thought of having multiple repositories for Dapper and for Entity Framework and I can register the one which I need in my dependency injection container. But in this case, all the methods from IStudentRepository interface needs to be implemented in both the EF and Dapper concrete repository classes (if I could do this in Dapper completely, then I don't need EF at all).
Approach 2 : Then I thought about a more ugly approach and it is like exposing a property of IDbConnection along with the DbContext property (in this case SchoolContext) in the above StudentRepository class.
So the example would be like
public class StudentRepository : IStudentRepository, IDisposable
{
private SchoolContext context;
private IDbConnection Db;
public StudentRepository(SchoolContext context)
{
this.context = context;
this.db = new SqlConnection(ConfigurationManager.ConnectionStrings["conn"].ConnectionString);
}
public IEnumerable<Student> GetStudents()
{
return context.Students.ToList();
}
public IEnumerable<Student> GetStudentsBasedOnSomeComplexCondition()
{
//I can use the db property here and work with dapper in this case.
}
(The inclusion of the IDbConnection property can be done through an abstract class so as not to repeat the instantiation code of this property and to easily change the connection string in case if needed. I am adding it in the same class for simplicity).
Approach 3 : Now, I thought of separating it further which I again think is an ugly way. Along with StudentRepository which has only EF stuff (like the first example), I will have another concrete class called StudentDapperRepository which inherits from StudentRepository.
All the methods in StudentRepository will be changed to virtual. So, I will be using StudentDapperRepository for my actual data layer and this will have the Dapper implementations where needed and where not needed, it will use the base class StudentRepository methods (which is in EF).
I think all my solutions are ugly and adding more complexity and confusion. So, can I have some light into how I can do this.

EntityFramwork generating Interfaces for MEF

I am playing around building some buildingblocks based on database tables.
So I've created an UsersManager and a ValidationManager both based on the EDMX "templates".
I'd really like to loose couple those two components with MEF. But therefore i need to create Interfaces of the entityobjects exposed in the ValidationManager.
Is there an easy way of creating those Interfaces, in that manner i can still use the EDMX generated classes?
Thanx,
Paul
Using an example of a database with a Product Table, is this what you're trying to achieve....
but still use generated entity classes (using either the standard EF generator or another POCO generator of some sort).
I'm not sure - as you mention MEF and I don't see it being directly related.
The generated entity classes are partial classes which will allow you to extend the generated class which in this case you want to extend to implement an interface.
Presuming the following interface is going to be used to introduce the layer of abstraction...
public interface IEntity {
public bool IsDeleted { get; set; }
}
Create a new class file with and extended Product class...
public partial class Product : IEntity {
public bool IsDeleted {
get {
throw new NotImplementedException();
}
set {
throw new NotImplementedException();
}
}
}
You have now extended your generated entity Product with the partial class custom code - and you can use it as normal through EF.
Now instead of your UserManager and ValidationManager classes having a hard reference to Product, instead they'll only have reference to IEntity.
If I didn't understand the question, please provide more details on exactly it is you want to do.