Spring Data JPA Method naming contains query for double value - mysql

i have an entity which contains some attributes and i want to write a like (contains) query for all of its attributes with one single parameter from front controller. i have successfully achieved it for the String values but for the numeric (long, double) values, i cannot use containing keyword as it throws an exception (Parameter value ['%10%'] did not match expected type java.lang.Double()... something...).
my entity fields
private String firstName;
private double rating;
my repository query method
List<MobileUser> findByFirstNameIgnoreCaseContainingOrRatingContaining(String value, double value2);
my service layer method which takes only one value
public List<MobileUserDTO> getMobileUsersLike(String value) {
// parses the value and if it is not a numeric value it will be -1 (this is also a bad logic)
Double parseDouble = (double) -1;
try { parseDouble = Double.parseDouble(value); } catch (NumberFormatException ignored) { }
// calls repository
List<MobileUser> allUsersLike = mobileUserRepository.findByFirstNameIgnoreCaseContainingOrRatingContaining(value, parseDouble);
return getMobileUserDtoList(allUsersLike);
}
how do i achieve this? thank you.

You can try to use JPQL query:
#Query("FROM MobileUser WHERE firstName like %:firstName% OR CAST(rating AS TEXT) LIKE %:rating% ")
List<MobileUser> findByNameAndRating(#Param("name") String firstName, #Param("rating") String rating);
You can't use SQL like for double unless you cast it to String.

Related

ServiceStack.OrmLite: Implementing custom StringConverter affects column type of complex BLOB fields

In a previous SO question I asked how I change the MySql column type when I have string properties in my POCOs.
The answer, which I answered myself, was to implement my own StringConverter. It was sort of an acceptable approach, I thought.
However, in my answer, I noted that not only was my string properties affected, so was all those properties that are complex and where OrmLite BLOBs them as JSON.
The field types for those complex columns in MySQL also became like varchar(255), which of course doesn't last very long.
The StringConverter was very short and easy:
I said that default string length is 255:
StringConverter converter = OrmLiteConfig.DialectProvider.GetStringConverter();
converter.StringLength = 255;
I wanted string props defined as 255 chars or smaller to be varchar(255)
string props defined as > 255 and < 65535 to be text
string props defined as >= 65535 to be longtext
MyStringConverter:
public class MyStringConverter : StringConverter
{
public override string GetColumnDefinition(int? stringLength)
{
if (stringLength.GetValueOrDefault() == StringLengthAttribute.MaxText)
return MaxColumnDefinition;
if (stringLength.GetValueOrDefault(StringLength) <= 255)
{
return UseUnicode
? $"NVARCHAR({stringLength.GetValueOrDefault(StringLength)})"
: $"VARCHAR({stringLength.GetValueOrDefault(StringLength)})";
}
else if (stringLength.GetValueOrDefault(StringLength) <= 65535)
{
return $"TEXT";
}
else
{
return "LONGTEXT";
}
}
}
But, as stated above, a property that looks like this (ActionInfo just contains some strings and List):
public List<ActionInfo> _AvailableActions { get; set; }
produced a table like this when using MyStringConverter:
Without using MyStringConverter, the column became a longtext.
Question is then: what am I missing? I still want complex, BLOBed fields to become longtext so that JSON BLOBing can be done. I was hoping that the StringConverter only affected string properties?
The column definition of blobbed complex types should use the ReferenceTypeConverter which by default resolves to DialectProvider.GetStringConverter().MaxColumnDefinition;
You should inherit the RDBMS-specific MySqlStringConverter if you want to change the string behavior of MySQL Strings otherwise you will revert back to inheriting generic RDBMS behavior which uses VARCHAR(8000) for strings and MaxColumnDefinition.
Alternatively you can override MaxColumnDefinition in your own String converter:
public override string MaxColumnDefinition => "LONGTEXT";

Can a logback message field be truncated/trimmed to n characters?

Sometimes see huge log messages and do not always have the ability to (easily) turn of word wrapping.
Is there a way to truncate %message to, say, 80 characters via logback.xml?
Have a look at the format modifiers section:
From http://logback.qos.ch/manual/layouts.html#formatModifiers:
Format modifiers
By default the relevant information is output as-is. However, with the aid of format modifiers it is possible to change the minimum and maximum width and the justifications of each data field.
...
Truncation from the end is possible by appending a minus character right after the period. In that case, if the maximum field width is eight and the data item is ten characters long, then the last two characters of the data item are dropped.
The Adrian's answer is great if you only need to truncate the message. However in my case I wanted to add "... [truncated]" in case of the really truncated messages.
I used a custom convertors mechanism for this purpose - by performing the following steps:
Define you custom converter:
public class LongMessagesConverter extends ClassicConverter {
private static final int MAX_FORMATTED_MESSAGE_LENGTH = 25600;
private static final String TRUNCATION_SUFFIX = "... [truncated]";
private static final int TRUNCATED_MESSAGE_SIZE =
TRUNCATION_SUFFIX.length() + MAX_FORMATTED_MESSAGE_LENGTH;
#Override
public String convert(ILoggingEvent event) {
String formattedMessage = event.getFormattedMessage();
if (formattedMessage == null ||
formattedMessage.length() < MAX_FORMATTED_MESSAGE_LENGTH) {
return formattedMessage;
}
return new StringBuilder(TRUNCATED_MESSAGE_SIZE)
.append(formattedMessage.substring(0, MAX_FORMATTED_MESSAGE_LENGTH))
.append(TRUNCATION_SUFFIX)
.toString();
}
}
Add to your logback.xml the following definition:
<conversionRule conversionWord="boundedMsg" converterClass="your.package.LongMessagesConverter"/>
Replace %msg token with %boundedMsg in your message format pattern

Select column from non-generic DbSet?

I want to implement a function that accepts a DbSet (non-generic), a string, and object, and returns DbSet. something like the following pseudu:
public static DbSet Any(DbSet set, string propertyName, objectParameter)
{
var tableName = set.TableName;
var columnName = set.GetColumnNameForProperty(propertyName);
var query = string.Format("SELECT TOP(1) {0} FROM {1} WHERE {0} = {2}",
columnName,
tableName,
objectParameter);
}
I think that SQL query is enough since I'll be able to execute it directly on the Database (context.Database.ExecuteSql).
What I want to do is get the table name from the given DbSet, then the column name in the database.
It is not possible from non generic DbSet but this problem can be easily solved by using:
public static IEnumerable<T> Any(DbSet<T> set, string property, objectParameter)
where T : class
{ ... }
Returning DbSet doesn't make sense because once you query data it is not DbSet anymore.
The bigger problem is getting table name from generic DbSet / ObjectSet because this information is not available from those classes. It is almost impossible to get it at all because it requires accessing non public members of items from MetadataWorkspace.

LINQ to SQL Dynamic Sort question

How do I code the Select clause in my LINQ satament to select column aliases so I can sort on them basically I want to accomplish this SQL statement in LINQ:
select
type_id as id,
type_desc as description
from
dbo.equip_type_avt
order by
description
What do I replace the ????? in my .Select clause in my LINQ statement?
public IQueryable<equip_type_avt> GetGridEquipmentTypes(string sidx, string sord)
{
try
{
return
ulsDB.equip_type_avts
.Select(?????)
.OrderBy(sidx + " " + sord);
}
catch (Exception ex)
{
string strErr = ex.Message;
return null;
}
}
You can use an anonymous type:
table.Select(x => new
{
ID = x.type_id,
Description = x.type_desc
});
However, you can't access the properties of an anonymous type outside of the scope where it is declared (without reflection or other dirty hackery, anyway) so if you want to use the result outside of that function you just create a class and create an instance of it in the query using a type initializer:
public class Foobar
{
public int ID { get; set; }
public string Description { get; set; }
}
...
table.Select(x => new Foobar() // Note the difference here
{
ID = x.type_id,
Description = x.type_desc
});
Question though: if you want to name the columns differently, why don't you change it in the place where the column-property mapping is declared? In LINQ-to-SQL you can have the database column be named whatever you like but give the property the name "ID" or "Description".
I'm not sure i understand your question, how does sidx and sord relate to your query?
Isn't your problem rather that you have to end your query with OrderBy(...).ThenBy(...) instead of a combined OrderBy?
If you want to sort by a string in the easy way, download the Dynamic LINQ library.
However, that's 2000 lines of code, most of which are entirely redundant for just the purpose of sorting.
Doing it yourself shouldn't be too hard, but requires a fair bit of knowledge on expression trees. I can't really help you there though.
EDIT: I've added another answer, that hopefully answers your actual question :)

LINQ + type tables best practices

Whats the best design pattern to use for LINQ and type tables that exist in SQL.
I have tables in SQL that constrain values to type values, and I want to be able to use this in my C# code as strongly typed values.
My current approach for a 'PackageStatus' type is as follows:
SQL Table
PackageStatusType (int)
desc (varchar)
C# Class - using LINQ
public class PackageStatusType
{
static PackageStatusType()
{
var lookup = (from p in DataProvider.ShipperDB.PackageStatus
select p).ToDictionary(p => p.Desc);
Unknown = lookup["Unknown"];
LabelGenerated = lookup["Label generated"];
ReadyForCollection = lookup["Ready for pickup"];
PickedUp = lookup["Picked up"];
InTransit = lookup["In Transit"];
DeliveryAttempted = lookup["Delivery attempted"];
DeliveredByHand = lookup["By hand"];
DeliveryFailed = lookup["Delivery failed"];
Delivered = lookup["Delivered"];
Voided = lookup["Voided"];
}
public static ShipperDB.Model.PackageStatus Unknown;
public static ShipperDB.Model.PackageStatus LabelGenerated;
public static ShipperDB.Model.PackageStatus ReadyForCollection;
public static ShipperDB.Model.PackageStatus PickedUp;
public static ShipperDB.Model.PackageStatus InTransit;
public static ShipperDB.Model.PackageStatus DeliveryAttempted;
public static ShipperDB.Model.PackageStatus DeliveryFailed;
public static ShipperDB.Model.PackageStatus Delivered;
public static ShipperDB.Model.PackageStatus DeliveredByHand;
public static ShipperDB.Model.PackageStatus Voided;
}
I then can put PackageStatusType.Delivered in my C# code and it will correctly reference the right LINQ entity.
This works fine, but makes me wonder:
a) how can i make this more efficient
b) why doesn't Microsoft seem to provide anything to create strongly typed type tables
c) is my database design even a good one?
d) what is everyone else doing!
thanks!
Linq to SQL allows you to map a string or int column in a database to an enumeration in your C# code. This allows you to let Linq to SQL to map these values for you when you select from the database. In this case, I would change my package status column to be either an int column with the values from the enumeration or a string that represents the values from the enumeration.
In your case, I would have a PackageStatus enumeration with the different values that you specified, and then using the ORM designer or SQLMetal, map that column to that enumeration. The only caveat is that the string values in the column in the database must match the values in the enumeration as Linq to SQL will use Enum.Parse() to map the string values from the database to the enumeration or make sure that the int values in the database match the values from the enumeration.
This is more efficient as you don't even need to map the lookup table at all in the code.
http://msdn.microsoft.com/en-us/library/bb386947.aspx#EnumMapping describes how this works.