Is there a possibility to check if multiple columns of an entity contain one search key in JPA - jpa

Is there a possibility to check if multiple or every column of an entity contains one key.
So I have multiple places which contain multiple addresses.
An address does contain the id of its place, a name and an area. I want to filter out the addresses which contain a searchTerm s1 in either its name or area.
I did already try this, but sadly it didnt work for me.
fun findByPlaceIdAndNameIgnoreCaseOrAreaIgnoreCaseContaining(placeId: UUID, searchTerm: String)

Sure this is possible. Just but the appropriate query in a #Query annotation.
I don't know Kotlin so the syntax is guess work on my side but I'm sure you figure it out based on this:
#Query("SELECT p FROM Place p WHERE p.placeId = :placeID AND (UCASE(p.name) = UCASE(:searchTerm) OR UCASE(p.name) = UCASE(:searchTerm))")
fun search(placeId: UUID, searchTerm: String)

Related

Spring JPA Specification API with custom Query and custom response Object. Is this possible?

I have researched this for a few days but can't seem to find the right information.
Here is what I need, I have a Database, with multiple tables, I need to join a few tables together to make a sort of "search" API. I have to implement the ability to dynamically search fields (from various tables in the query), sortable, with pagination.
I have found that I cannot combine the #Query annotation with Specification API, and I looked into using the specification API to do the joins I needed but, the problem is the root must be one table/repository.
For example:
If I have a users table that has to join on addresses, phone_numbers, and preferences
the base repository will be UserResposiory and it will return the User entity model, but I need it to return a custom DTO
AccountUserDTO which contains fields from the User, Address, PhoneNumber, and Preference entities.
Would anyone know if this is possible at all??
I am at wits end here and I really want to build this the correct way.
Cheers!
You may do this way:
Build hql query as an string, depend on how the filter condition is requested, you can build the corresponding query, eg:
if (hasParam(searchName)) {
queryString = queryString + " myEntity.name = :queryName"
}
Query query = session.createQuery(queryString);
and the parameter providing
if (hasParam(searchName)) {
query.setParameter("queryName", searchName);
}
...
and execute it.
To create a customized object, the easiest way is treating the object as an array of field:
Query query = session.createQuery("select m.f1, m.f2, m.f3 from myTable m");
List managers = query.list();
Object[] manager = (Object[]) managers.get(0); //first row
System.out.println(manager[0]) //f1
System.out.println(manager[1]) //f2
System.out.println(manager[2]) //f3
There is also some other solution to select, such as
String query = "select new mypackage.myclass(m.f1, m.f2, m.f3) from myTable m";
-> And when execute the above query, it will return a list of object.
Or to be simpler, make your own view in db and map it to one entity.

Eloquent Friendly Column Name

We're currently transitioning from one database to another. A table in our legacy database has column names that are less than ideal, for example:
some_crazy_name__xyz
In our new database, we'd like to have a column name like:
someCrazyName
In the short term, we have to work with data from our legacy database. At some point in the near future, we'd like to switch over without having to refactor all of our Eloquent code to query for different column names. For example:
$model = MyModel::where('someCrazyName', '=', 1);
I'm currently extending the Model class, where all implementing models provide a map of terrible names to friendly names:
class MyModel extends BaseModel {
$columnMap = array(
'someCrazyName' => 'some_crazy_name__xyz'
);
}
This works well where I can use __get and __set in BaseModel to lookup properties in my map, for example:
$myModel = new MyModel;
// ...
echo $myModel->someCrazyName;
However, this obviously doesn't work well with queries without having to always use my map to look up column names. I'm wondering if it's possible without having to override all of the methods within Illuminate\Database\Eloquent\Model, Illuminate\Database\Query\Builder and Illuminate\Database\Eloquent\Builder that deal with columns, where the underlying query that is built always maps to the correct column? Then after we transition databases, we can remove that one piece of code rather then remove potentially thousands of column name mappings.
This is what you need: https://github.com/jarektkaczyk/eloquence/wiki/Mappable
It's not only for mapping badly_named_columns to something_useful, but also can be used for relational mappings:
// simple aliasing
User::where('cool_name', 'value') // where badName = ?
// relations, eg. User hasOne Profile
User::where('first_name', 'Jon') // search through related profiles table
// and obviously mutators:
$user->first_name == $user->profile->first_name
$user->cool_name = 'Jon' // becomes $user->badName = 'value'
$user->cool_name; // 'Jon'
One way to do it would be with accessors.
For example, in MyModel you could define an accessor for the some_crazy_name__xyz column like this:
public function getSomeCrazyNameAttribute()
{
return $this->attributes['some_crazy_name__xyz'];
}
You can then transparently refer to that column with $mymodel->someCrazyName. You can also define a mutator to set the value.
Admittedly, this may not be the best solution if you have MANY values like this. But it does have one important benefit: later on, if you refactor your database so that the column some_crazy_name__xyz is actually called someCrazyName, all you need to do is remove that function from your model. And, to my mind at least, it's simpler than trying to override a bunch of methods on the various classes involved.
And unfortunately, it doesn't adequately address the use of column names in queries. For that, you might want to look at the repository pattern. But in any event, it looks like there's going to be a lot of coding involved.
Finally, you haven't mentioned what database you're using. If it's MySQL, it is possible to create updatable and insertable views. Using a view, you could simply map old column names to new, and point your Eloquent model at the view instead of a table. Other database servers may provide similar functionality.

What is the best method for L2E Join in following scenario?

Following are two tables:
Country >> CountryId, CountryName
City >> CityId, CityName, CountryId
I am using repository pattern to generate entity set from database. (example, repository.GetQuery<City>())
Now I want to write such a query that when I fetch City it also generates an populates for corresponding Country in the result set. So I can just access it like, city.Country.CountryName.
I know I can perform this by joining two entity sets, but that must be costly in performance. Probably, .Include<> may help me in achieving this. Any idea/ example to achieve this?
I'm going to assume, since you're using Entity Framework, that your City object has a navigational property of Country which points to the corresponding Country record.
As such, unless you specifically want to use lazy loading, you'll need to use Include. The good news is that you can do the includes inside of your repositories, and not have to write that code on the outside. An example of this can be found here.
Let me know if that works.

MyBatis mapping properties to database columns when inserting & updating (using annotations)

I'm just starting to learn MyBatis and I'm wondering, when I'm creating insert or update queries, is there a way that I can make property names a bit more friendly to refactoring? I'll explain in more detail:
I have constants in all of my domain classes that can be used to reference property names. In my opinion, it cuts down on typos and makes refactoring a bit easier.
public static final String FIRST_NAME = "firstName";
private String firstName = "";
When I create a MyBatis select statement using annotations, I can do something like this:
#Select("SELECT ID, FIRST_NAME, LAST_NAME FROM CUSTOMERS WHERE ID = #{id}")
#Results({
#Result(property = CustomerDetail.ID, column = "ID"),
#Result(property = CustomerDetail.FIRST_NAME, column = "FIRST_NAME"),
#Result(property = CustomerDetail.LAST_NAME, column = "LAST_NAME")
})
CustomerDetail selectById(final int id);
If I refactor my domain object (CustomerDetail) and change property names, it ends up being fairly simple.
However, when I create a MyBatis insert statement using annotations, I have to do something like this:
#Insert("INSERT INTO CUSTOMERS (ID, FIRST_NAME, LAST_NAME) VALUES (#{id}, #{firstName}, #{lastName})")
void insertCustomerDetail(final CustomerDetail customerDetail);
In this case, if I refactor my domain object (CustomerDetail) and change property names, it's much more error prone. Is there a way I can use my constants without resorting to a bunch of string concatenation? Is it something I should even concern myself with?
As a total newbie, I was expecting the #Insert and #Update annotations to mimic the structure of the #Select annotation. For example (please note, the below are NOT valid MyBatis annotations):
#Insert("INSERT INTO CUSTOMERS (ID, FIRST_NAME, LAST_NAME)")
#Params({
#Param(property = CustomerDetail.ID, column = "ID"),
#Param(property = CustomerDetail.FIRST_NAME, column = "FIRST_NAME"),
#Param(property = CustomerDetail.LAST_NAME, column = "LAST_NAME")
})
void insertCustomerDetail(final CustomerDetail customerDetail);
Have I missed any options that would have the same effect as my above sample? Alternatively, is it possible for me to unit test MyBatis mappings to ensure no one is using property names that don't exist in my domain objects? Testing may be a better solution since it would also apply to XML based mappings. Thoughts?
Is it something I should even concern
myself with?
I don't think so. I understand your concern, and I see how such a feature could be beneficial to you, especially early in development when POJO's tend to change so often.
I don't think your objects fields will be refactored enough to justify the investment needed to provide this functionality.
I suggest you read about the #Param tag in the mybatis user guide. It's not exactly what your looking for here, but it is a way to decouple object field names to mybatis sql map variables. In my mind, I would take your approach over passing in individual feilds with a #Param.
In regards to unit testing your sql maps, i'm fairly certain that if you use an ognl expression that doesn't have a corresponding get method in the object you'll get an exceptions. i.e if you use #{someField}, and the object your passing in doesn't have a getSomeField() method, then you get exception.

Access the property used in mapping entity to a table in EFv4

When we have two entities in EFv4 EDM diagram and only one table for both in the database (for instance, having table Documents and entities Invoice and Qoute), table Documents having documentTypeId column as a discriminator and set this column as a discriminator in the EDM (in Table mappings), how do we read the value of this property in our code?
We cannot assign values to it because EF does it for us under the hood (based on what we entered in Table mappings for condition) but somehow I don't get it why we are also not allowed to read it.
Imo this property is already mapped so you can't map it again. It is used to determine type of materialized entity. Why do you need such column. Usually it is enough to use is operator like:
var document = context.Documents.GetById(id);
if (document is Invoice)
{
...
}
If you only need to select subtypes you can use OfType extension method like:
var invoices = context.Documents.OfType<Invoice>().ToList();
You also don't need to set this value when adding new entity because you are adding subtype - Invoice or Quote.
Edit:
As I understand from your comment you don't need this information in query. In such case you don't need to map it. Simply use partial class of your entity and add custom property which will return your string. Sound like stupid solution but actually it would be the easiest one.
Discriminator column should be part of mapping metadata so in case of T4 template generating your entities, it could be possible to update the template so it generate such property for you.
You may want to use a single-table inheritance hierarchy, as described here.
That way, you could have an abstract Document class that includes a DocumentTypeId column. Invoices and Quotes would extend this class, but specify certain DocumentTypeId filters. However, because the original class has a DocumentTypeId column, they would each have that column as well.
Another advantage to this approach is that you could create utility methods that can act on any Document, and you could pass any Invoice or Quote to these methods.