I have a database with four tables. TableA and TableB are the main tables and the TableC is the table of the many to many relationships.
TableA(IDTableA, Name...)
TableB(IDTableB, Name...)
TableC(IDTableA, IDTableB)
This create three entities, The EntityA has an ICollection of Entity C and Entity C has a Collection of EntitiesB, so when I try to get the related entities I do this:
myContext.EntityA.Include(a=>a.EntityB.Select(b=>b.EntityC));
But this throw and exception that says that the collection is null.
So I would like to know if it is possible to do an eager loading when there are a table for the many to many relationship.
Thanks.
I think you need this:
var q = myContext.EntityC.Include("EntityA").Include("EntityB").ToList();
If you want Bs of an A:
var aId; // = something...;
var bs = from c in q
where c.EntityAId == aId
select c.EntityBId;
And simply vice versa if you need As of a B:
var bId; // = something...;
var eas = from c in q
where c.EntityBId == bId
select c.EntityAId;
With many to many association in Entity Framework you can choose between two implementations:
The junction table (C) is part of the conceptual model (class model) and the associations are A—C—B (1—n—1). A can't have a collection of Bs.
The junction table is not part of the conceptual model, but Entity Framework uses it transparently to sustain the association A—B (n—m). A has a collection of Bs and B has a collection of As. This is only possible when table C only contains the two FK columns to A and B.
So you can't have both.
You (apparently) chose the first option, so you will always have to query the other entites through C, like
from a in context.As
select new { a, Bs = a.Cs.Select(c => c.B) }
or
from a in As.Include(a1 => a1.Cs.Select(c => c.B))
Related
I'm trying to do a flexibleSearch to retrieve Products and his Leaf Categories. The leaf categories are the last categories that have no other subcategories, and the categories must be of type "category" and "productTypeCategory". I try to make some joins but I failed. I appreciate any help!
I would suggest something like this:
SELECT {c.code}, {c.itemtype}, {ccr.source} FROM
{Category as c LEFT JOIN CategoryCategoryRelation as ccr ON {c.pk}={ccr.source}
JOIN ComposedType as ct ON {c.itemtype} = {ct.pk}}
WHERE {ccr.source} IS NULL AND {ct.code} = 'Category'
At least, it should be a beginning. It will return the LEAF cats of type Category.
The rest is Joining with Products and probably considering catalog versions. Depending on the concrete use case you haven't provided, it is maybe better to ask Solr for the final result and you use the category result of my query to pass to the solr query, instead of implementing the additional JOINs, but that depends on if you're in the storefront or if you need the info for a backoffice/cronjob etc.
I have two models Reference and Product, Reference has many Product and I need to run the next query (with some Loopback's method) so I doesn't get the empty products.
SELECT DISTINCT R.id
FROM Reference R
WHERE EXISTS (
SELECT id FROM Product P
WHERE P.referenceId = R.id AND P.stock > 0
)
Thanks!
Currently is not posible to query a model filtering based on a related model property using the built-in methods/query language, check this issue. So you will have to execute your sql using the datasource connector. That is for example if you have a model file called Reference.js:
var dbConnection = Reference.dataSource.connector;
dbConnection.execute(yourSql, [], function (err, references) {});
The result will be an array of objects with only the id property. Check this
Another option could be do the relation bidirectional (Product belongs to Reference) and query for products having stock > 0, but you are going to have to group the repeated values:
var Product = Reference.app.models.Product;
Product.find({where: {stock: {gt:0}}, fields: {referenceId:true}}, function (err, prods) {})
How can I get a list of table names and definitions by either SQL statement or code behind for the Starcounter DB?
Metadata about created tables, their columns and indexes are stored in meta-data tables. Database classes are publicly exposed for corresponding meta-data tables.
Tables or types are described by Starcounter.Metadata.RawView and Starcounter.Metadata.ClrClass and both extends Starctouner.Metadata.Table. ClrClass contains description for loaded CLR classes only, while RawView describes all created tables. They include descriptions of user-defined classes/tables and metadata classes/tables.
For example, all loaded user-defined classes can be enumerated:
foreach(ClrClass c in Db.SQL<ClrClass>(
"select c from Starcounter.Metadata.ClrClass c where Updatable = ?", true)) {
Console.WriteLine(c.FullName);
}
Property Updatable of Table is true for user-defined tables and false for meta-data/system tables.
Properties or columns are described by Starcounter.Metadata.Member and its children. An example of enumerating all columns for all user-defined tables is:
foreach(Member m in Db.SQL<Member>(
"select m from Column m, RawView v where m.Table = v and v.Updatable = ?",
true)) {
Console.WriteLine(m.Name);
}
Indexes are described by Starcounter.Metadata.Index and Starcounter.Metadata.IndexedColumn.
Currently it is one-to-one match between database classes and tables. However, this and metadata schema might change in future.
I'm trying to get an average for a count on a groupBy by joining with a subquery. Don't know if that the right way to go at all but I couldn't anything about subqueries other than the mysema doc.
Scenario:
How many orders per product did a customer do on average?
Meaning: A Customer orders products. So a customer ordered a specific product a number of times (count). What's the average number of orders that customer placed for any product?
Might sound a bit hypothetical, in fact it's just part of a prototype, but it made me wonder, how to get a reference to a custom column created within a subquery with the fancy QueryDSL from Mysema.
In SQL you just give the count column an alias and join using a second ID column. QueryDSL has the "as()" method as well but I have no Idea, how to retrieve that column plus I dont't see how it can join one query with anothers, since query.list() just gets a list but for some reason the join accepts it. Feels wrong...
Here's my code:
JPQLQuery query = createJPQLQuery();
QOrdering qOrdering = QOrdering.ordering;
QProduct qProduct = QProduct.product;
QCustomer qCustomer = QCustomer.customer;
// how many of each product did a customer order?
HibernateSubQuery subQuery = new HibernateSubQuery();
subQuery.from(qOrdering).innerJoin(qOrdering.product,qProduct).innerJoin(qOrdering.customer, qCustomer);
subQuery.groupBy(qCustomer,qProduct).list(qCustomer.id,qProduct.id,qProduct.count());
// get the average number of orders per product for each customer
query.from(qCustomer);
query.innerJoin(subQuery.list(qCustomer.id,qOrdering.count().as("count_orders")));
query.groupBy(qCustomer.id);
return (List<Object[]>) query.list(qCustomer.firstname,subQuery.count_orders.avg());
Again: How do I join with a subquery?
How do I get the aliased "count" column to do more aggregation like avg (is my group right btw?)
Might be that I have some other errors in this, so any help appreciated!
Thanks!
Edit:
That's kind of the native SQL I'd like to see QueryDSL produce:
Select avg(numOrders) as average, cust.lastname from
customer cust
inner join
(select count(o.product_id) as numOrders, c.id as cid, p.name
from ordering o
inner join product p on o.product_id=p.id
inner join customer c on o.customer_id=c.id
group by o.customer_id, o.product_id) as numprods
on cust.id = numprods.cid
group by numprods.cid
order by cust.lastname;
Using subqueries in the join clause is not allowed. in JPQL, subqueries are only allowed in the WHERE and HAVING part. The join method signatures in Querydsl JPA queries are too wide.
As this query needs two levels of grouping, maybe it can't be expressed with JPQL / Querydsl JPA.
I'd suggest to write this query using the Querydsl JPA Native query support.
As Querydsl JPA uses JPQL internally, it is restricted by the expressiveness of JPQL.
I know that this question is old and already has an accepted answer, but judging from this question, it seems to still be troubling guys. See my answer in the same question. The use of JoinFlag in the join() section and Expression.path() is able to achieve left-joining a subquery. Hope this helps someone.
QueryDsl does not support subQuery in join but you can achieve this via following way:
We wanted to achieve the following query:
select A.* from A join (select aid from B group by aid) b on b.aid=A.id;
Map a View or SQL query to JPA entity:
import lombok.Setter;
import org.hibernate.annotations.Subselect;
import org.hibernate.annotations.Synchronize;
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
#Getter
#Setter
#Subselect("select aid from B group by aid")
#Synchronize("B")
public class BGroupByAid {
#Id
private Integer aId;
}
then use the equivalent QueryDSl entity in the class just like the regular entity:
JPAQuery<QAsset> query = new JPAQuery<>(entityManager);
QBGroupByAid bGroupById = QBGroupByAid.bGroupByAid;
List<A> tupleOfAssets =
query.select(A)
.from(A).innerJoin(bGroupById).on(bGroupById.aId.eq(A.aId))
.fetchResults()
.getResults();
You can also use blazebit which supports also subquery in join. I have try it and it is working. You can create SubQueryExpression f.e like this
SubQueryExpression<Tuple> sp2 = getQueryFactory().select(entity.id,
JPQLNextExpressions.rowNumber().over().partitionBy(entity.folId).orderBy(entity.creationDate.desc()).as(rowNumber))
.from(entity)
.where(Expressions.path(Integer.class, rowNumber).eq(1));
and then just join it like this:
return getBlazeQueryFactory()
.select(entity1, entity)
.from(entity1)
.leftJoin(sp2, entity).on(entity.id.eq(entity1.id)).fetch();
I have put here just simple example. So maybe it doesn't make a perfect sense but maybe can be helpful.
Also don't be confused it will can produce union in the generated select. This is just for naming columns from subquery you can read better explanation about this union here: Blaze-Persistence GROUP BY in LEFT JOIN SUBQUERY with COALESCE in root query
I want to perform a simple join on two tables (BusinessUnit and UserBusinessUnit), so I can get a list of all BusinessUnits allocated to a given user.
The first attempt works, but there's no override of Select which allows me to restrict the columns returned (I get all columns from both tables):
var db = new KensDB();
SqlQuery query = db.Select
.From<BusinessUnit>()
.InnerJoin<UserBusinessUnit>( BusinessUnitTable.IdColumn, UserBusinessUnitTable.BusinessUnitIdColumn )
.Where( BusinessUnitTable.RecordStatusColumn ).IsEqualTo( 1 )
.And( UserBusinessUnitTable.UserIdColumn ).IsEqualTo( userId );
The second attept allows the column name restriction, but the generated sql contains pluralised table names (?)
SqlQuery query = new Select( new string[] { BusinessUnitTable.IdColumn, BusinessUnitTable.NameColumn } )
.From<BusinessUnit>()
.InnerJoin<UserBusinessUnit>( BusinessUnitTable.IdColumn, UserBusinessUnitTable.BusinessUnitIdColumn )
.Where( BusinessUnitTable.RecordStatusColumn ).IsEqualTo( 1 )
.And( UserBusinessUnitTable.UserIdColumn ).IsEqualTo( userId );
Produces...
SELECT [BusinessUnits].[Id], [BusinessUnits].[Name]
FROM [BusinessUnits]
INNER JOIN [UserBusinessUnits]
ON [BusinessUnits].[Id] = [UserBusinessUnits].[BusinessUnitId]
WHERE [BusinessUnits].[RecordStatus] = #0
AND [UserBusinessUnits].[UserId] = #1
So, two questions:
- How do I restrict the columns returned in method 1?
- Why does method 2 pluralise the column names in the generated SQL (and can I get round this?)
I'm using 3.0.0.3...
So far my experience with 3.0.0.3 suggests that this is not possible yet with the query tool, although it is with version 2.
I think the preferred method (so far) with version 3 is to use a linq query with something like:
var busUnits = from b in BusinessUnit.All()
join u in UserBusinessUnit.All() on b.Id equals u.BusinessUnitId
select b;
I ran into the pluralized table names myself, but it was because I'd only re-run one template after making schema changes.
Once I re-ran all the templates, the plural table names went away.
Try re-running all 4 templates and see if that solves it for you.