JPAQuery/QueryDSL Fetch all entities that have a specific item in list (#OneToMany)? - jpa

In resume, I have this:
Purchase {
#OneToMany
Set<Item> items;
}
Item {
Long id;
}
How can I get a list of Purchase that have a specific Item in the list?
This is what I tried to do (probably not the correct way):
QPurchase purchase ...
JPAQuery query ...
query.from(purchase).where(
purchase.items.any().id.eq(xxx)
);
But I always get a SQLException Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.

Solved:
QPurchase purchase ...
QItem item ...
JPAQuery query ...
query.from(purchase).
.join(purchase.item, item)
.where( item.id.eq(xxx) );

Related

EF Core 5 - Including only one entity from collection

How do you include just a single entity per "main" entity in a query where the navigational property is a collection?
await _database.Table1
.AsQueryable()
.Include(t1 => t1.Table2.Where(t2 => t2.Id == t1.SingleTable2Id))
.FirstOrDefaultAsync();
The above doesn't seem to work. I get the following exception:
could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
Try this:
IQueryable query= _dbcontext.Table1
.AsQueryable();
As Queryable creates an expression tree that is not evaluated until fetch
you can add where expressions to your tree dynamically and assess include tables automatically.
Product[] products =
{
new Product {ProductId=1, Name="Kayak",Category="Watersports",Price=275m, Company=new Company{ CompanyName="Abc Corp",States=new String[]{"Ut","Id" } } },
new Product {ProductId=2, Name="Lifejacket", Category="Watersports",Price=48.95m, Company=new Company{ CompanyName="X Corp",States=new String[]{"Ca","Az" } }},
new Product {ProductId=3, Name="Soccer Ball", Category="Soccer",Price=19.50m, Company=new Company{ CompanyName="Y Corp",States=new String[]{"Tx","Wa" } }},
new Product {ProductId=4, Name="Corner Flag", Category="Soccer",Price=34.95m, Company=new Company{ CompanyName="Z Corp",States=new String[]{"Co","Wy" } }}
};
IQueryable<Product> query = products.
Where(e => e.Name == "Kayak")
.AsQueryable<Product>();
Product item = query.FirstOrDefault<Product>();
_output.WriteLine($"Item Name: {item.Name} Company: {item.Company.CompanyName}");

How can I determine how many rows were loaded into an EF6 DbContext when using Load/LoadAsync?

The DbContext DbSet<T>.Load / DbSet<T>.LoadAsync methods return void and Task respectively: they execute queries and then add the loaded/instantiated entity objects into the DbContext's DbSet and update the navigation properties and reverse-navigation of already-loaded objects, but they don't return any information about what they loaded: there doesn't seem to be a way of getting the actual count of the number of rows that were loaded.
Which is surprising, considering that the SaveChanges / SaveChangesAsync method does return the number of rows affected by any DML statements it executes.
I know there's a workaround in that I could use ToList/ToListAsync instead and then use the List<T>.Count property, but that's defeating the point of using Load/LoadAsync.
For example, consider this two-step query operation:
async Task<PageViewModel> LoadOrdersAsync( Int32 customerId, Expression<Func<Order,Boolean>> predicate )
{
// Step 1:
List<Order> orders = await this.dbContext.Orders
.Where( o => o.CustomerId == customerId )
.Where( predicate )
.ToListAsync()
.ConfigureAwait(false);
// Step 1.5:
List<Int32> orderIds = orders.Select( o => o.OrderId ).ToList();
// Step 2:
await this.dbContext.OrderItems
.Where( i => orderIds.Contains( i.OrderId ) )
.LoadAsync()
.ConfigureAwait(false);
// Done!
return new PageViewModel( orders );
}
I want to get the quantity of OrderItem entities that were loaded in the second step, but as far as I know that isn't possible without using ToList/ToListAsync.
You’re right, there is no easy way to get the number of loaded entries of the Load. It is essentially the same as ToList without creating the list and adding the loaded elements to it. If you really don’t want to use ToList, one option is to access the DbContext.ChangeTracker and get the number of entries from that:
var entriesBefore = context.ChangeTracker.Entries().Count();
// load more entities
var loaded = context.ChangeTracker.Entries().Count() - entriesBefore;
Note, that this is not accurate when you include other, related entities in your query.

SpringData Cassandara findAll method returns only one record

Creating a project with SpringData using Reactive Cassandra repository. I have sample Book application where I wrote custom query.
#GetMapping("/books2")
public Flux<Book2> getBooks(#Valid #RequestBody Book2 book ){
MapId id1 = id( "id", book.getId()).with("isbn", book.getIsbn());
if(Objects.nonNull(book.getName()))
id1.with( "name", book.getName());
if(Objects.nonNull(book.getLocalDate()))
id1.with( "localDate", book.getLocalDate());
return book2Repository.findAllById( Collections.singletonList(id1));
}
I have many rows but return result is only one.
Looking into code SimpleReactiveCassandraRepository.java,
public Flux<T> findAllById(Iterable<ID> ids) {
Assert.notNull(ids, "The given Iterable of ids must not be null");
if (FindByIdQuery.hasCompositeKeys(ids)) {
return this.findAllById((Publisher)Flux.fromIterable(ids));
} else {
FindByIdQuery query = FindByIdQuery.forIds(ids);
List<Object> idCollection = query.getIdCollection();
....
....
public Flux<T> findAllById(Publisher<ID> idStream) {
Assert.notNull(idStream, "The given Publisher of ids must not be null");
return Flux.from(idStream).flatMap(this::findById);
}
The findAllById seem to check if Query has composite key and calls "findAllById" which seem to call findById , which return single record.
How do i get to return multiple rows ?
Is this a bug ?
I tried with 2.2.7 and 3.0.1 spring-data-cassandara and results seems same.

multiple nested navigation properties EF ?

i have in my database a User has list of Subscriptions, each subscription has a Category, each category has list of Paths, each path has list of Articles ?
Model
class User {
ICollection<Subscription> Subscriptions;
}
class Subscription {
Category category;
}
class Category {
ICollection<Path> paths;
}
class Path{
ICollection<Article> Articles;
}
my question
How to retrieve all Articles for a specific user ?
Using a combination of Select and SelectMany statements, you are able to traverse your entities and find the collection you need:
var allUserArticles = myUser.Subscriptions
.Select(sub => sub.Category) //take the category from each subscription
.SelectMany(cat => cat.Paths) //Take each path from each category, put them in a single list
.SelectMany(path => path.Articles) //Take each article from each path, put them in a single list
.ToList();
Note that if these entities need to be loaded from your database, that EF either needs to implement eager loading, or you have to make sure that all needed related entities are retrieved before running the above statement. Unexpected nulls can cause your output to be incorrect.
However, I have no info on this as it is missing from the question, so I can't know your specific case.

MongoDB and NoRM - Querying collection against a list of parameters

I need to query a collection based on a list of parameters.
For example my model is:
public class Product
{
string id{get;set;}
string title{get;set;}
List<string> tags{get;set;}
DateTime createDate{get;set;}
DbReference<User> owner{get;set;}
}
public class User
{
string id{get;set;}
...other properties...
}
I need to query for all products owned by specified users and sorted by creationDate.
For example:
GetProducts(List<string> ownerIDs)
{
//query
}
I need to do it in one query if possible not inside foreach. I can change my model if needed
It sounds like you are looking for the $in identifier. You could query products like so:
db.product.find({owner.$id: {$in: [ownerId1, ownerId2, ownerId3] }}).sort({createDate:1});
Just replace that javascript array [ownerId1, ...] with your own array of owners.
As a note: I would guess this query is not very efficient. I haven't had much luck with DBRefs in MongoDB, which essentially adds relations to a non-relational database. I would suggest simply storing the ownerID directly in the product object and querying based on that.
The solution using LINQ is making an array of user IDs and then do .Contains on them like that:
List<string> users = new List<string>();
foreach (User item in ProductUsers)
users .Add(item.id);
return MongoSession.Select<Product>(p => users .Contains(p.owner.id))
.OrderByDescending(p => p.createDate)
.ToList();