How to join with the same table two times in jOOQ? - spring-boot

I have table which have one-to-one relation with another, but there are two of them, src and dst, how to join it right? I did something like that, but not sure this is best practce:
val route = tbl.`as`("route")
val srcPlace = Tables.PLACE.`as`("srcPlace")
val dstPlace = Tables.PLACE.`as`("dstPlace")
val records = dsl
.select(route.asterisk())
.select(srcPlace.asterisk())
.select(dstPlace.asterisk())
.from(route)
.join(srcPlace).on(route.SRC_ID.eq(srcPlace.ID))
.join(dstPlace).on(route.DST_ID.eq(dstPlace.ID))
.limit(pageable.pageSize)
.offset(pageable.offset)
.fetch {
val r = it.into(route).into(RouteEntity::class.java)
val sP = it.into(srcPlace).into(PlaceEntity::class.java)
val dP = it.into(dstPlace).into(PlateEntity::class.java)
r.srcPlace = sP
r.dstPlace = dP
r
}
How to do it better?

The easiest way (starting from jOOQ 3.17 and the ability of projecting table expressions as SelectField) is to just project the tables themselves, e.g.:
dsl.select(route, srcPlace, dstPlace)
. // query
.fetch {
val (r, sP, dP) = it
// ...
}
In your particular case, you can even simplify things further by using implicit joins
// Assuming you named your foreign keys "src" and "dst"
dsl.select(route, route.src, route.dst)
.from(route)
.limit(pageable.pageSize)
.offset(pageable.offset)
.fetch {
val (r, sP, dP) = it
// ...
}
Or even, without the it destructuring:
// Assuming you named your foreign keys "src" and "dst"
dsl.select(route, route.src, route.dst)
.from(route)
.limit(pageable.pageSize)
.offset(pageable.offset)
.fetch { (r, sP, dP) ->
// ...
}

Related

add data to an arrayList, when If condition is satisfied in nested for loop in Kotlin

Check the code below:
getCommonsArrayList(listA:ArrayList< User >, listB:ArrayList<User>):ArrayList<User>{
var listCommon = ArrayList<User>()
for (i in listA.indices) {
for (j in listB.indices) {
if (listA[i].id.equals(listB[j].id)) { //if id of the user matches
listCommon.put(listA[i]) //add to a new list
}
}
}
return listCommon // return the new list with common entries
}
The above method iterates list a & b and check whether the id's are matching, if they are then the User object is stored to a new list and at the end of the program, it returns the common list.
This thing works good. And I hope nested for followed by if condition is the way in which we can compare two lists.
The problem with this is if listA has repeated entries, then the listCommon will also have repeated entries as ArrayList supports duplicacy of entries.
So what I did to make commonList unique is I introduced a HashMap object as shown below:
getCommonsArrayList(listA:ArrayList< User >, listB:ArrayList<User>):ArrayList<User>{
var listCommon = ArrayList<User>()
var arrResponseMap = HashMap<String,User>()
for (i in listA.indices) {
for (j in listB.indices) {
if (listA[i].id.equals(listB[j].id)) { //if id of the user matches
arrResponseMap.put(listA[i].id,listA[i]) // add id to map so there would be no duplicacy
}
}
}
arrResponseMap.forEach {
listCommon.add(it.value) //iterate the map and add all values
}
return listCommon // return the new list with common entries
}
This will give the new arrayList of userObject with common Id's. But this has an increased complexity than the above code.
If the size of the listA and listB increases to 1000 then this execution will take heavy time.
Can someone guide me if there is some better way to solve this.
You can simply use distinctBy to get only unique values from list.
Official Doc:
Returns a sequence containing only elements from the given sequence
having distinct keys returned by the given selector function.
The elements in the resulting sequence are in the same order as they
were in the source sequence.
Here is an example:
val model1 = UserModel()
model1.userId = 1
val model2 = UserModel()
model1.userId = 2
val model3 = UserModel()
model1.userId = 1
val model4 = UserModel()
model1.userId = 2
val commonList = listOf(model1, model2, model3, model4)
// get unique list based on userID, use any field to base your distinction
val uniqueList = commonList
.distinctBy { it.userId }
.toList()
assert(uniqueList.count() == 2)
assert(commonList.count() == 4)
Add the both the list and use distinctBy like this
data class DevelopersDetail(val domain: String, val role: String)
val d1 = DevelopersDetail("a", "1")
val d2 = DevelopersDetail("b", "1")
val d3 = DevelopersDetail("c", "1")
val d4 = DevelopersDetail("c", "1")
val d5 = DevelopersDetail("d", "1")
var listA = listOf(d1, d2, d3, d4)
var listb = listOf(d1, d2, d3, d4)
var data = listA + listb
var list= data
.distinctBy { it.domain }
.toList()
println("list $list")
//output-list [DevelopersDetail(domain=a, role=1), DevelopersDetail(domain=b, role=1), DevelopersDetail(domain=c, role=1)]

IN operator in Couchbase Lite

I need to query something like
SELECT * FROM `sample` WHERE id IN ["123", "456"]
This is converted into QueryBuilder as below
QueryBuilder
.select(SelectResult.all())
.from(DataSource.database("sample"))
.where(Expression.property("id")
.in([
Expression.string("123"),
Expression.string("456")
])
)
This doesn't work, and return empty list of result, any idea?
I see from your comments that your code worked (it was false negative). Yet I'll share an approach which may be useful in case you need to use the like operator against multiple wildcarded (%) expressions. Sample is in Kotlin language:
val list = listOf("123", "456")
val items = list.map { Meta.id.like(Expression.string("$it-%")) }.toMutableList()
val whereExpression = items
.fold(items.removeAt(0)) { chain, next -> chain.or(next) }
val query = QueryBuilder.select(
SelectResult.expression(Meta.id),
SelectResult.all()
).from(DataSource.database(this.db)).where(whereExpression)
val results = query.execute()
val resultList = results.allResults()

Most efficient way to determine if there are any differences between specific properties of 2 lists of items?

In C# .NET 4.0, I am struggling to come up with the most efficient way to determine if the contents of 2 lists of items contain any differences.
I don't need to know what the differences are, just true/false whether the lists are different based on my criteria.
The 2 lists I am trying to compare contain FileInfo objects, and I want to compare only the FileInfo.Name and FileInfo.LastWriteTimeUtc properties of each item. All the FileInfo items are for files located in the same directory, so the FileInfo.Name values will be unique.
To summarize, I am looking for a single Boolean result for the following criteria:
Does ListA contain any items with FileInfo.Name not in ListB?
Does ListB contain any items with FileInfo.Name not in ListA?
For items with the same FileInfo.Name in both lists, are the FileInfo.LastWriteTimeUtc values different?
Thank you,
Kyle
I would use a custom IEqualityComparer<FileInfo> for this task:
public class FileNameAndLastWriteTimeUtcComparer : IEqualityComparer<FileInfo>
{
public bool Equals(FileInfo x, FileInfo y)
{
if(Object.ReferenceEquals(x, y)) return true;
if (x == null || y == null) return false;
return x.FullName.Equals(y.FullName) && x.LastWriteTimeUtc.Equals(y.LastWriteTimeUtc);
}
public int GetHashCode(FileInfo fi)
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
hash = hash * 23 + fi.FullName.GetHashCode();
hash = hash * 23 + fi.LastWriteTimeUtc.GetHashCode();
return hash;
}
}
}
Now you can use a HashSet<FileInfo> with this comparer and HashSet<T>.SetEquals:
var comparer = new FileNameAndLastWriteTimeUtcComparer();
var uniqueFiles1 = new HashSet<FileInfo>(list1, comparer);
bool anyDifferences = !uniqueFiles1.SetEquals(list2);
Note that i've used FileInfo.FullName instead of Name since names aren't unqiue at all.
Sidenote: another advantage is that you can use this comparer for many LINQ methods like GroupBy, Except, Intersect or Distinct.
This is not the most efficient way (probably ranks a 4 out of 5 in the quick-and-dirty category):
var comparableListA = ListA.Select(a =>
new { Name = a.Name, LastWrite = a.LastWriteTimeUtc, Object = a});
var comparableListB = ListB.Select(b =>
new { Name = b.Name, LastWrite = b.LastWriteTimeUtc, Object = b});
var diffList = comparableListA.Except(comparableListB);
var youHaveDiff = diffList.Any();
Explanation:
Anonymous classes are compared by property values, which is what you're looking to do, which led to my thinking of doing a LINQ projection along those lines.
P.S.
You should double check the syntax, I just rattled this off without the compiler.

Update class field in LINQ - is it possible?

I have 2 tables, and want to get records from 1 table and to "update" one of its fields from another table, and to pass final list of "Payment" objects somewhere. I cannot use anonymouse type, i need to get the list of proper typed objects.
There was a long way.
Got data:
var paymentsToShow = from p in paymentsRepository.Payments
join r in recordTypeRepository.RecordType
on p.RecordType equals r.Reference into p_r
where p.Customer == CustomerRef
from r in p_r.DefaultIfEmpty()
select new
{
Payment = p,
RecordType = r
};
var objList = paymentsToShow.ToList();
Change required field (basically, Payment.RecordTypeName is empty):
foreach (var obj in objList)
{
obj.Payment.RecordTypeName = obj.RecordType.Name;
}
Got list with correct type:
var paymentsList = from o in objList
select o.Payment;
Is there any way to get code shorter, to make required field update in the query or something else? I dont know where to look for.
I cannot change database.
You could do it like this:
var paymentsToShow = (from p in paymentsRepository.Payments
join r in recordTypeRepository.RecordType
on p.RecordType equals r.Reference into p_r
where p.Customer == CustomerRef
from r in p_r.DefaultIfEmpty()
select new
{
Payment = p,
RecordType = r
}).Select(x =>
{
x.Payment.RecordTypeName = x.RecordType.Name;
return x.Payment;
});
This will result in an IEnumerable<Payment>, so no anonymous type used.

dot notation equivalent for JOIN

string[] names = { "Burke", "Connor", "Frank",
"Albert", "George", "Harris", "David" };
peoples[] people = {
new peoples("Connor",20),
new peoples("John",22),
new peoples("Merry",33),
new peoples("Frank",65),
new peoples("Frank",34),
new peoples("George",19)
};
var query = from n in names
join p in people on n equals p.Name into matching
select new { Name = n, Count = matching.Count() };
Please tell me dot notation of this query.
Thanks.
The dot notation for a join depends on what follows it and whether or not you've got an "into" clause (for a group join). In this case it would be:
var query = names.GroupJoin(people, n => n, p => p.Name,
(n, matching) => new { Name = n, Count = matching.Count() });
If you didn't use "into" it would use Join instead of GroupJoin
If you had anything other than just "select" afterwards, it would introduce a new transparent identifier to keep "(n, matching)" as a tuple, effectively.

Resources