I have kind of 'restaurant app' with multi tenant architecture. Each Tenant in short words have their Order table where I keep all data regarding orders which were made.
I also have a User/Client table which is in public schema, cause each Client can make order in different restaurants (tenants).
Problem: The problem which came in my implementation is that I'd like to display to the client all orders that he made.
Question: How can I query through all (or provided) Tenants to query such data?
Current CurrentTenantIdentifierResolver looks like:
public String resolveCurrentTenantIdentifier() {
return Optional
.ofNullable(TenantContext.getTenantSchema())
.orElse(PUBLIC_TENANT);
}
Whenever a user visits a tenant (Restaurant), you will be storing the Tenant's (AKA Restaurants) id that the user is in now as part of UserTenants or some other table like this.
When a consolidated orders list is required, you can run a query in the above table to get the list of all tenants (Restaurants) that the user has been to and then for each of the tenant, setup the context for the tenant (the one that helps setup the schema in the datasource) and you should be able to pull the data.
You can run the queries in parallel across all the tenant schema and then concatenate them all to get the full list of orders.
Related
Hi there i need help I'm new to caching data. I'm using ehcache in spring application using xml configuration and I want to use different keys on different method to find same record. Suppose, one method is annotated like this:
#Cacheable(value="getCustomerByAreaId",key="T(java.lang.String).valueOf(#areaid)")
public List<Customer> getCustomerByAreaId(String areaid) {
//code
return customerList;
}
it will return all the customers having same area id. This list will be stored in the cache as each customer have unique customer id. Can I use some mechanism to fetch single customer record from cache= getCustomerByAreaId based on customer id.
#Cacheable(value="getCustomerByAreaId",key="T(java.lang.String).valueOf(#customerId)")
public Customer getCustomerById(long customerId) {
// code
return customer;
}
I know if I make key like this it will enter a new record in the cache (getCustomerByAreaId) with the new key.
Instead I want to fetch record from list that is already being cached.
If it is possible can I do this using xml or java.
I'm using ehcache version 2.5.
This is not possible simply by using Ehcache APIs or Spring's caching abstraction.
If you want to achieve this, you will have to program your own logic to cache the list but also its elements individually.
I have a database with this structure.
I am using JSP + Servlet + Entity Classes from database + Session Beans for entity classes. As you can see, my tables are normalized which in return makes it necessary to join tables to obtain the whole details of a patient/staff. As i studied the https://netbeans.org/kb/docs/javaee/ecommerce/intro.html i saw that they access the database by using the facade.find etc and etc. Considering my case, I have also tried using the same thing.
For example. I have a session bean (Profile Manager) which accesses the entities and puts it in the map.
public Map getPatientDetails(int patientID)
{
Map patientMap = new HashMap();
Patient patient = patientFacade.find(patientID);
User user = userFacade.find(patient.getUserId().getId());
UserContact userContact = user.getUserContact();
Family family = familyFacade.find(patient.getFamilyId().getId());
String patientDOB = new SimpleDateFormat("MMMMM dd, yyyy").format(user.getDateOfBirth());
patientMap.put("familyRecord", family);
patientMap.put("patientRecord", patient);
patientMap.put("patientDOB", patientDOB);
patientMap.put("userRecord", user);
patientMap.put("userContactRecord", userContact);
return patientMap;
}
As I give myself time to think about it, I thought that I can join the entities by using and setting a namedquery instead making it a single access. Which is the right way to do this? Do you think using facades to access my database is better than constructing an inner join query to acheive getting all the information at once? What would you guys suggest? Thanks!
I would suggest you to avoid joins in your SQL as, in my experience, it is one of the main root cause of performance issues associated to data access layer.
I would suggest to fetch entity one by one (like hibernate). In this method, there will be round trips to the database. But the SQLs will be simple and thus faster.
I'm in the middle of fumbling around with JPA. I've so far successfully created an entity representing the user data and a stateless bean for the access to the user data.
The data the users can work on is like this (SQLFiddle link):
CREATE TABLE data
(
email character varying(128) NOT NULL,
data character varying(128) NOT NULL,
lastchange timestamp NOT NULL,
CONSTRAINT email_data PRIMARY KEY (email,data)
);
The idea is to save the unaltered, current version for all users with an empty email key. Then, when a user alters the data and creates an auditable version, the email field is filled with the users email. This way, each user can alter their copy of the data. The merging is a problem for a later date and not part of my question.
Now, I have the entities already in place. I created a stateless bean to load/save/find the data records by using the EntityManager. The logic to load the user specific version first, then load the unaltered version if the user has no user specific version still eludes me.
Consider this part of the bean:
#Stateless
public class DataBean {
#PersistenceContext(unitName = "authPU")
private EntityManager em;
public List<DataEntry> findAll() {
TypedQuery<DataEntry> query = em.createQuery("SELECT d FROM data d", DataEntry.class);
List<DataEntry> list = query.getResultList();
return query.getResultList();
}
...
}
How do I inject the user information into this class? I need to get the data for the current user first, then get the data for all users if there's no user-specific data available.
You could use standard EJB authentication. Then you can call SessionContext.getCallerPrincipal() in your session bean to get a user ID. Use this user ID to query the database.
In this case you have to add another column to your table (containing the user ID), if the authentication user ID does not equal the email address.
Far simpler (but less elegant) is to add the email address to the arguments of your EJB service method: Just make it part of the public API.
I am using Spring JDBC and I am a bit unsure on how to work with multiple one-to-many relations (or many-to-many). In this case I am injecting a repository into one of my resultsetextractors so that I can retrieve its associations. Is this the way to do it? Is it bad? Are there other better ways?
Note: I have left out the injection of repository
public class SomeResultSetExtractor implements ResultSetExtractor {
public Object extractData(ResultSet rs) throws SQLException, DataAccessException {
List result = new LinkedList();
while (rs.next()) {
SomeObject object = new SomeObject(rs.getString(1), rs.getLong(2));
result.add(object);
List<AnotherObject> otherObjects = anotherRepository.findAllById(object.getId);
object.setOtherObjects(otherObjects);
// and so on
}
return result;
}
}
Okey so after reading Dmytro Polivenok answer I have changed to RowMapper interface instead and I am currently using the other repositories to populate all associations like I show in my example. Is this a good way of doing it?
I think a good practice for Spring JDBC and SQL queries in general is to use one query for each entity.
E.g. assume this model:
Customer (customerId, name, age, ...)
Address (customerId, type, street, city, ...)
PaymentOption (customerId, cardnumber, cardtype, ...)
Customer 1---* Address
Customer 1---* PaymentOption
I would build 3 queries, 3 Daos, 3 ResultSetExtractors/RowcallbackHandlers:
CustomerDao with readCustomerData(Customer or List)
AddressDao with readAddressForCustomer(Customer or List)
PaymentOptionDao with readPaymentOptionsForCustomer(Customer or List)
If you would bake this in 1 query, you would have to build some logic to revert the cartasian product.
I.e. if the customer has 3 addresses and 2 payment options the query would return 6 rows.
This gets quite hard, if Address or PaymentOption does not have an own primary key.
For many to many:
Customer * --recommends-- * Product
I would probably build:
CustomerDao.readRecommendationsAndProductKeys
getDistinctListOfProductKeysFromRecommendations
ProductDao.readProducts
replaceProductKeysByProductsOnRecommendations
Like this you could reuse ProductDao.readProducts for
Customer * --buys-- * Product or
ProductGroup 1---* Product
I think that your code will work, but the concern here is about usage of ResultSetExtractor which is mainly for JDBC framework itself, and for most cases documentation recommends to use RowMapper.
So alternative approach would be to have method in your DAO that selects and maps parent object. Then for each object to invoke other Repository or private method that selects and maps child objects, and then to link child objects with parents based on your relationship type (one-directional or bidirectional). This approach may also allow you to control whether you want to load child objects or not.
For example, you may check Spring PetClinic application which has SimpleJdbcClinic class
If you can use other frameworks, you may consider mybatis, it is more about mapping and allows you to control your SQL code.
I'm just getting to grips with JPA in a simple Java web app running on Glassfish 3 (Persistence provider is EclipseLink). So far, I'm really liking it (bugs in netbeans/glassfish interaction aside) but there's a thing that I want to be able to do that I'm not sure how to do.
I've got an entity class (Article) that's mapped to a database table (article). I'm trying to do a query on the database that returns a calculated column, but I can't figure out how to set up a property of the Article class so that the property gets filled by the column value when I call the query.
If I do a regular "select id,title,body from article" query, I get a list of Article objects fine, with the id, title and body properties filled. This works fine.
However, if I do the below:
Query q = em.createNativeQuery("select id,title,shorttitle,datestamp,body,true as published, ts_headline(body,q,'ShortWord=0') as headline, type from articles,to_tsquery('english',?) as q where idxfti ## q order by ts_rank(idxfti,q) desc",Article.class);
(this is a fulltext search using tsearch2 on Postgres - it's a db-specific function, so I'm using a NativeQuery)
You can see I'm fetching a calculated column, called headline. How do I add a headline property to my Article class so that it gets populated by this query?
So far, I've tried setting it to be #Transient, but that just ends up with it being null all the time.
There are probably no good ways to do it, only manually:
Object[] r = (Object[]) em.createNativeQuery(
"select id,title,shorttitle,datestamp,body,true as published, ts_headline(body,q,'ShortWord=0') as headline, type from articles,to_tsquery('english',?) as q where idxfti ## q order by ts_rank(idxfti,q) desc","ArticleWithHeadline")
.setParameter(...).getSingleResult();
Article a = (Article) r[0];
a.setHeadline((String) r[1]);
-
#Entity
#SqlResultSetMapping(
name = "ArticleWithHeadline",
entities = #EntityResult(entityClass = Article.class),
columns = #ColumnResult(name = "HEADLINE"))
public class Article {
#Transient
private String headline;
...
}
AFAIK, JPA doesn't offer standardized support for calculated attributes. With Hibernate, one would use a Formula but EclipseLink doesn't have a direct equivalent. James Sutherland made some suggestions in Re: Virtual columns (#Formula of Hibernate) though:
There is no direct equivalent (please
log an enhancement), but depending on
what you want to do, there are ways to
accomplish the same thing.
EclipseLink defines a
TransformationMapping which can map a
computed value from multiple field
values, or access the database.
You can override the SQL for any CRUD
operation for a class using its
descriptor's DescriptorQueryManager.
You could define a VIEW on your
database that performs the function
and map your Entity to the view
instead of the table.
You can also perform minor
translations using Converters or
property get/set methods.
Also have a look at the enhancement request that has a solution using a DescriptorEventListener in the comments.
All this is non standard JPA of course.