Symfony 2 many-to-many sql translate to dql - sql

I'm having a problem with mapping a many-to-many relationship I've never encountered before. I have two entity document, exam, and relation many-to-many document2exam.
Information:
Entity/Document.php,
class Document {
private $id;
private $entryNumber;
private $isPaymentFree;
private $profile;
private $dateCreated;
private $dateModified;
private $exams;
private $invoice;
}
Entity/Exam.php
class Exam {
private $name;
private $examCode;
private $dateTime;
private $startOnlineRegDate;
private $endOnlineRegDate;
private $endChangeDate;
private $session;
private $link;
private $documents;
private $isWriting;
private $examService;
}
Resources/Document.orm.xml
<many-to-many field="exams" inversed-by="documents" target-entity="\Entity\Exam">
<join-table name="document2exam">
<join-columns>
<join-column name="document_id" referenced-column-name="id" nullable="false" on-update="CASCADE" on-delete="CASCADE" />
</join-columns>
<inverse-join-columns>
<join-column name="exam_id" referenced-column-name="id" nullable="false" on-update="CASCADE" on-delete="CASCADE" />
</inverse-join-columns>
</join-table>
<cascade>
<cascade-all />
</cascade>
</many-to-many>
Resources/Exam.orm.xml
<many-to-many field="documents" mapped-by="exams" target-entity="\Entity\Document" />
My SQL is:
SELECT en.entry_number, en.exam_id
FROM Data_ExamNotes en
WHERE exam_id = 3
AND en.entry_number NOT IN (
SELECT d.entry_number
FROM Document d
INNER JOIN document2exam d2e ON d.id = d2e.document_id
WHERE d2e.exam_id = 3
AND d.entry_number is not null
)
ORDER BY en.entry_number ASC
I cant write dql query because of document2exam table.
Thank you, and sorry for my language :)

I found the answer of my question.
$em = $this->getEntityManager();
$query = $em->createQuery(
"SELECT en.entryNumber as enNum, IDENTITY(en.exam) as ex
FROM UcictDataBundle:ExamNotes en
WHERE en.exam = :exam
AND en.entryNumber NOT IN (
SELECT d.entryNumber
FROM UcictStudentBundle:Document d
INNER JOIN d.exams e
WHERE e.id = :exam
AND d.entryNumber is not null
)
ORDER BY en.entryNumber ASC");
$ret = $query
->setParameter('exam', $exam)
->getResult();
return $ret;

Related

Hibernate: join with 2 NOT primary key

i want to do a left outer join from 2 table, but with 2 key that are not primary key.
This is the native sql query used:
Maybe there is a better way to do it?
SQLQuery query = session.createSQLQuery("
select {A.*},{B.*} from A_TABLE A left outer join B_TABLE B on A.QUOTE_ID = B.QUOTE_NUM ")
.addEntity("A", A_Class.class)
.addJoin("B", "A.bDocs");
for(Object result : query.list())
{
....
}
The mapping A file:
<class name="A_Class" table="A_TABLE" schema="S">
<id name="rowId" type="string">
<column name="ROW_ID" length="60" />
<generator class="assigned" />
</id>
<set name="BDocs" inverse="true" fetch="select" lazy="false">
<key>
<column name="QUOTE_NUM" length="60" not-null="true" />
</key>
<one-to-many class="B_Class" />
</set>
A_Class.java
public class A_Class implements java.io.Serializable
{
private String rowId;
private String QuoteId;
private Set BDocs= new HashSet(0);
// omitted all the set and get
}
The mapping B file:
<hibernate-mapping>
<class name="B" table="B_TABLE" schema="S">
<id name="rowId" type="string">
<column name="ROW_ID" length="60" />
<generator class="assigned" />
</id>
<many-to-one name="A" class="A_Class" fetch="select" lazy="false" outer-join="true" foreign-key="QuoteId" property-ref="QuoteId">
<column name="QUOTE_NUM" length="60" not-null="true" />
</many-to-one>
B_Class.java
public class B_Class implements java.io.Serializable
{
private String rowId;
private String quoteNum;
// omitted all the set and get
}
From this query i obtain 2 objects, one of A type and the other of B Type with a lot of correct datas but the set BDocs in the object of A type isn't filled. The goal is to get only the A Object with the variable BDocs filled with the B Objects.
I don't understand if the problem is in the query or in the mapping files. Anyone can help me?

HQL Query SELECT with NOT IN

I need a HQL Query but I just dont get it.
SELECT * FROM Poll WHERE pid NOT IN (
SELECT pid FROM votes WHERE uid = 'theuserid')
I want all List of PollĀ“s back where the uid not in the table votes exists.
Also helpfull would be the hql query where the uid in the table votes exists, but I guess this is very similar ;-)
These are the 2 classes:
public class Poll {
private int pid;
private String name;
private String description;
private Date deadline;
private Set<Team> teams = new HashSet<Team>(0);
//some getter & setter
}
public class Vote {
private int vid;
private String uid;
private int pid;
private int tid;
private int votes;
//some getter & setter
}
Can smbdy please help me. I guess it is a join with a WHERE and NOT LIKE but I just dont get it.
Merci!
This is btw the hibernate mapping:
<hibernate-mapping>
<class name="package.model.Poll" table="poll">
<id name="pid" column="pid" >
<generator class="increment"/>
</id>
<property name="name" column="name" />
<property name="description" column="description" />
<property name="deadline" type="timestamp" column="deadline" />
<set name="teams" table="pollchoice"
inverse="false" lazy="false" fetch="select" cascade="all" >
<key>
<column name="pid" not-null="true" />
</key>
<many-to-many entity-name="knt.exceedvote.model.Team">
<column name="tid" not-null="true" />
</many-to-many>
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="package.model.Vote" table="votes">
<id name="vid" column="vid" >
<generator class="increment"/>
</id>
<property name="pid" column="pid" />
<property name="uid" column="uid" />
<property name="tid" column="tid" />
<property name="votes" column="votes" />
</class>
</hibernate-mapping>
Please keep in mind, Hibernate is designed using the notion of Object Graph, which is a name given to the relational objects.
That core concept is missing in your mapping (Poll and Vote seem to be isolated) hence I doubt you can use HQL in its current state.
In my opinion, you have two options:
Define the relationship between Poll, pid and Vote, uid. Then you should be able to write simple HQL.
Use native SQL through Hibernate session itself.

Convert a SQL query to a Hibernate Criteria expression

I'm having trouble converting this expression to a Criteria expression:
SELECT profile_profiles.profile_sup_id
FROM profil
INNER JOIN profile_profiles ON profile_profiles.profile_id = profil.id
AND profil.id = 4
Can anyone help?
i have one table 'Profil' Many to Many and refelxive
Profil 1 --- profile_profiles --- Profil 2
public class Profil implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String libelle;
private Set<Profil> profiles = new HashSet<Profil>(0);
...
}
hbm
<set name="profiles" table="profile_profiles" cascade="all">
<key column="profile_id" />
<many-to-many column="profile_sup_id" class="com.steriamedshore.proboard.model.referentiel.Profil" />
</set>
Criteria c = session.createCriteria(Profil.class, "profil");
c.createAlias("profil.profiles", "supProfil");
c.add(Restrictions.eq("profil.id", 4);
c.setProjection(Projections.property("supProfil.id"));
The above should, AFAIK, make an additional join from the join table to the profile table, but it should return the same thing as your SQL query.
thank you very much #JB Nizet
I did actually find the solution yesterday :
hibernateCriteria.createCriteria("profil").createAlias("profiles", "ps").add( Restrictions.eq("ps.id",superieurCriteria.getProfilId()) ) ;
peace.

NHibernate - Left joins

I have the following two tables:
Jobs AreaID, JobNo (composite key)
Logs LogID, AreaID, JobNo
I need to get all jobs that don't have any logs associated with them. In SQL I could do:
SELECT Jobs.AreaID,
Jobs.JobNo
FROM Jobs
LEFT JOIN Logs
ON Jobs.AreaID = Logs.AreaID
AND Jobs.JobNo = Logs.JobNo
WHERE Logs.LogID is null
But I'm not sure how to accomplish this with NHibernate. Could anyone offer any pointers?
Here are my mappings:
<class name="Job" table="Jobs">
<composite-key name="Id">
<key-property name="JobNo"/>
<key-many-to-one name="Area" class="Area" column="AreaID"/>
</composite-key>
</class>
<class name="Log" table="Logs">
<id name="Id" column="LogID">
<generator class="identity"/>
</id>
<property name="JobNo"/>
<many-to-one name="Area" class="Area" column="AreaID"/>
</class>
Thanks
Update
OK, I modified Nosila's answer slightly, and this is now doing what I wanted:
Log logs = null;
return session.QueryOver<Job>()
.Left.JoinAlias(x => x.Logs, () => logs)
.Where(x => logs.Id == null)
.List<Job>();
I also had to add this to my Job mapping:
<bag name="Logs">
<key>
<column name="JobNo"></column>
<column name="DivisionID"></column>
</key>
<one-to-many class="Log"/>
</bag>
Thanks for the help. :)
I'm not familiar with composite identifiers as I don't use them so for all I know NHibernate will automatically create the proper left join. None the less, the (non-tested) query below should get you started.
Job jobAlias = null;
Log logAlias = null;
YourDto yourDto = null;
session.QueryOver<Job>()
// Here is where we set what columns we want to project (e.g. select)
.SelectList(x => x
.Select(x => x.AreaID).WithAlias(() => jobAlias.AreaID)
.Select(x => x.JobNo).WithAlias(() => jobAlias.JobNo)
)
.Left.JoinAlias(x => x.Logs, () => logAlias, x.JobNo == logAlias.JobNo)
.Where(() => logAlias.LogID == null)
// This is where NHibernate will transform what you have in your `SelectList()` to a list of objects
.TransformUsing(Transformers.AliasToBean<YourDto>())
.List<YourDto>();
public class YourDto
{
public int AreaID { get; set; }
public int JobNo { get; set; }
}
Note: You need NHibernate 3.2 in order to set join conditions.
Job job = null;
var jobsWithoutLogs = session.QueryOver(() => job)
.WithSubquery.WhereNotExists(QueryOver.Of<Log>()
.Where(log => log.Job == job)
.Select(Projections.Id()))
.List()
Update: i saw you added the mapping. The Above Code only works for the following mapping
<class name="Log" table="Logs">
<id name="Id" column="LogID">
<generator class="identity"/>
</id>
<many-to-one name="Job" >
<column name="JobNo"/>
<column name="AreaID"/>
<many-to-one />
</class>

nHibernate join query

i have two tables (graph representation - one table is nodes, other is link between nodes), and i want to write this query in nHibernate:
SELECT
distinct(t.id), t.NodeName, e.Fk_linkOne, e.Fk_linkTwo, e.RelationName
FROM Nodes t
INNER JOIN NodeRelation e ON t.Id=e.Fk_linkOne OR t.Id=e.Fk_linkTwo
where (e.Fk_linkOne =84 OR e.Fk_linkTwo=84 ) AND t.Id!=84
I did not find how to connect two tables wiht join, that have OR in it..
ICriteria criteriaSelect = Session
.CreateCriteria(typeof(NodeRelation ), "nodeRelations")
.CreateCriteria("nodeRelations.Node", "node",
NHibernate.SqlCommand.JoinType.InnerJoin)
You can only define your joins as per the associations you have defined in your mappings. As far as I know you can't define OR style relationships in Nhibernate. Consider using a self referential style graph representation.
public class Node
{
public IList<Node> Parents { get; set; }
public IList<Node> Children { get; set; }
}
<bag name="Parents" table="Node_Relation">
<key column="ChildId" />
<many-to-many class="Node" column="ParentId" />
</bag>
<bag name="Children" table="Node_Relation">
<key column="ParentId" />
<many-to-many class="Node" column="ChildId" />
</bag>
You should be using DetachedCriteria to get the same done. I am not sure about your query but I will jsut give a shot.
var dc1= DetachedCriteria.For(typeof( NodeRelation )).Add(Restrictions.Eq("Fk_linkOne", 84))
.SetProjection(Projections.Property("Fk_linkOne"));
var dc2= DetachedCriteria.For(typeof( NodeRelation )).Add(Restrictions.Eq("Fk_linkTwo", 84))
.SetProjection(Projections.Property("Fk_linkTwo"));
Session.CreateCriteria(typeof(Nodes))
.Add(Subqueries.PropertyIn("Id", dc1))
.Add(Subqueries.PropertyIn("Id", dc2))
.Add(Restrictions.Eq("Id", 84)).List<Nodes>;
Hope the above query is corrrect. please let me know if you cant get it to work after obs trying smethings and let me know wat u tried.
It always depends on your classes and not so much on your tables. Remember, you are using a ORM and you are working with a class model.
Assumed that your classes look like this:
class Node
{
List<Node> Relations { get; private set; }
List<Node> InverseRelations { get; private set; }
}
You may map it like this:
<class name="Node">
<!-- .... -->
<bag name="Relations" table="NodeRelation">
<key name="Fk_linkOne">
<many-to-many class="Node" column="Fk_linkTwo"/>
</bag>
<bag name="InverseRelations" table="NodeRelation" inverse="true">
<key name="Fk_linkTwo">
<many-to-many class="Node" column="Fk_linkOne"/>
</bag>
</class>
This way you get asymetrical relations (this means: when Node A relates to Node B, B isn't necessarily related to A, except of the InverseRelation of course). I don't know what you actually need, so this is an assumption based on your database design.
Your query may look like this:
from Node n
where
:x in elements(n.Relations)
or :x in elements(n.InverseRelations)
Note: x is an entity type, not just an id (you need to load it using session.Load<Node>(84)),
Another way for the samy query:
select distinct n
from Node n
inner join n.Relations e1
inner join n.InverseRelations e2
where e1.id = 84 or e2.id = 84
Or another way without the use of the inverse relations:
select n
from Node n, Node n2 inner join n.Relations e
where
(n = n2 and e.id = 84)
OR (n = e and n2.id = 84)
In criteria I would take the second solution and write it like this:
session.CreateCriteria<Node>("n")
.SetProjection(Projections.Distinct("n"))
.CreateCriteria("Relations", "e1")
.CreateCriteria("InverseRelations", "e2")
.Add(Expression.Or(
Expression.Eq("e1.id", 84),
Expression.Eq("e2.id", 84));