I have a relation many-to-many.
In Entity "Progetti" i have:
/**
*
* #var \Doctrine\Common\Collections\ArrayCollection $attivita
*
* #ORM\ManyToMany(targetEntity="Attivita", inversedBy="progetti",cascade={"persist", "remove" })
* #ORM\JoinTable(name="progetti_attivita",
* joinColumns={#ORM\JoinColumn(name="progetti_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="attivita_id", referencedColumnName="id")}
* )
*/
protected $attivita;
In Entity "Attività " i have:
/**
*
* #var \Doctrine\Common\Collections\ArrayCollection $progetti
* #ORM\ManyToMany(targetEntity="Progetti", mappedBy="attivita")
*/
protected $progetti;
Ok.
The JoinTable "progetti_attivita" has "attivita_id" and "progetti_id".
Now i added a new field to the JoinTable "progetti_attivita" and i called it "position". it's an integer.
I have the ProgettiType Form:
$builder
->add('nomeProgetto')
->add('descProgetto')
->add('noteProgetto')
->add('attivita', CollectionType::class, array(
'entry_type' => AttivitaType::class,
'allow_add' => true,
));
Ok.
I have the form that display all "attività " for "progetti".
My question is:
How can i say to Form to display "attivita" ordered by "position" ?
If you always want your collection to be ordered then you can add the OrderBy property to your Doctrine mapping:
http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/tutorials/ordered-associations.html
/**
* #ManyToMany(targetEntity="Attivita")
* #OrderBy({"position" = "ASC"})
**/
private $attivitas;
An alternative approach would be to add a getAttivitaOrdered method to your Progetti entity:
class Progetti
getAttivitaOrdered() // return ordered list
->add('attivitaOrdered', CollectionType::class ...
Not sure if you will need a setAttivitaOrdered method or not when you post.
And your question is actually a little bit confusing. Adding a property to your join table means that you need to use OneToMany and ManyToOne relations instead of ManyToMany. So a few more adjustments will be needed.
I am trying to multiply two fields and take their sum after joining three tables in Pig. However I keep on getting this error:
<file loyalty_program.pig, line 30, column 74> (Name: Multiply Type: null Uid: null)incompatible types in Multiply Operator left hand side:bag :tuple(new_details1::new_details::potential_customers::num_of_orders:long) right hand side:bag :tuple(products::price:int)
-- load the data sets
orders = LOAD '/dualcore/orders' AS (order_id:int,
cust_id:int,
order_dtm:chararray);
details = LOAD '/dualcore/order_details' AS (order_id:int,
prod_id:int);
products = LOAD '/dualcore/products' AS (prod_id:int,
brand:chararray,
name:chararray,
price:int,
cost:int,
shipping_wt:int);
recent = FILTER orders by order_dtm matches '2012-.*$';
customer = GROUP recent by cust_id;
cust_orders = FOREACH customer GENERATE group as cust_id, (int)COUNT(recent) as num_of_orders;
potential_customers = FILTER cust_orders by num_of_orders>=5;
new_details = join potential_customers by cust_id, recent by cust_id;
new_details1 = join new_details by order_id, details by order_id;
new_details2 = join new_details1 by prod_id, products by prod_id;
--DESCRIBE new_details2;
final_details = FOREACH new_details2 GENERATE potential_customers::cust_id, potential_customers::num_of_orders as num_of_orders,recent::order_id as order_id,recent::order_dtm,details::prod_id,products::brand,products::name,products::price as price,products::cost,products::shipping_wt;
grouped_data = GROUP final_details by cust_id;
member = FOREACH grouped_data GENERATE SUM(final_details.num_of_orders * final_details.price) ;
lim = limit member 10;
dump lim;
I even casted the result of count to int. It still keeps on throwing this error at me. I have no clue how to go about it.
Ok.. I think at first, you want to multiply no.of purchases with the price of each product and then you need total SUM of that multiplied value..
Even though this is a strange requirement, but you can go with below approach..
All you need to do is calculate the multiplication in final_details Foreach statement itself and simply apply the SUM for that multiplied amount..
Based on your load statements I created the below input files
main_orders.txt
6666,100,2012-01-01
7777,101,2012-09-02
8888,100,2012-01-09
9999,101,2012-12-08
6666,101,2012-09-02
9999,100,2012-07-12
9999,100,2012-08-01
6666,100,2012-01-02
7777,100,2012-09-09
orders_details.txt
6666,6000
7777,7000
8888,8000
9999,9000
main_products.txt
6000,Nike,Shoes,3000,3000,1
7000,Adidas,Cap,1000,1000,1
8000,Rebook,Shoes,4000,4000,1
9000,Puma,Shoes,25000,2500,1
Below is the code
orders = LOAD '/user/cloudera/inputfiles/main_orders.txt' USING PigStorage(',') AS (order_id:int,cust_id:int,order_dtm:chararray);
details = LOAD '/user/cloudera/inputfiles/orders_details.txt' USING PigStorage(',') AS (order_id:int,prod_id:int);
products = LOAD '/user/cloudera/inputfiles/main_products.txt' USING PigStorage(',') AS(prod_id:int,brand:chararray,name:chararray,price:int,cost:int,shipping_wt:int);
recent = FILTER orders by order_dtm matches '2012-.*';
customer = GROUP recent by cust_id;
cust_orders = FOREACH customer GENERATE group as cust_id, (int)COUNT(recent) as num_of_orders;
potential_customers = FILTER cust_orders by num_of_orders>=5;
new_details = join potential_customers by cust_id, recent by cust_id;
new_details1 = join new_details by order_id, details by order_id;
new_details2 = join new_details1 by prod_id, products by prod_id;
DESCRIBE new_details2;
final_details = FOREACH new_details2 GENERATE potential_customers::cust_id, potential_customers::num_of_orders as num_of_orders,recent::order_id as order_id,recent::order_dtm,details::prod_id,products::brand,products::name,products::price as price,products::cost,products::shipping_wt, (potential_customers::num_of_orders * products::price ) as multiplied_price;// multiplication is achived in last variable
dump final_details;
grouped_data = GROUP final_details by cust_id;
member = FOREACH grouped_data GENERATE SUM(final_details.multiplied_price) ;
lim = limit member 10;
dump lim;
Just for clarity I am dumping the output of final_details foreach statement as well.
(100,6,6666,2012-01-01,6000,Nike,Shoes,3000,3000,1,18000)
(100,6,6666,2012-01-02,6000,Nike,Shoes,3000,3000,1,18000)
(100,6,7777,2012-09-09,7000,Adidas,Cap,1000,1000,1,6000)
(100,6,8888,2012-01-09,8000,Rebook,Shoes,4000,4000,1,24000)
(100,6,9999,2012-07-12,9000,Puma,Shoes,25000,2500,1,150000)
(100,6,9999,2012-08-01,9000,Puma,Shoes,25000,2500,1,150000)
final output is below
(366000)
This code may help you, but Please clarify your requirement again
I have trouble creating a CdbCriteria with nested join. Here's the code in model (sorry it's in Indonesian. Hopefully anyone can understand the query):
public function report() {
$criteria=new CDbCriteria;
$criteria->alias = "p";
$criteria->select = "p.tanggal_transaksi,
MONTH( p.tanggal_transaksi ) AS bulan,
p.kode,
p.kode_supplier,
s.nama,
d.kode_bahan_baku,
b.nama_barang,
d.jumlah_kg,
d.jumlah_cones,
d.harga_satuan,
d.harga_satuan * d.jumlah_cones AS total,
FLOOR(d.harga_satuan * d.jumlah_cones * p.ppn / 100) AS ppn,
(d.harga_satuan * d.jumlah_cones) + FLOOR(d.harga_satuan * d.jumlah_cones * p.ppn / 100) AS total_akhir
";
$criteria->join = "JOIN m_supplier s ON s.kode = p.kode_supplier
RIGHT JOIN t_pembelian_detail d ON d.kode_pembelian = p.kode
JOIN m_bahan_baku b ON b.kode = d.kode_bahan_baku
";
$criteria->together = TRUE;
return new CActiveDataProvider(get_class($this), array(
'criteria'=>$criteria,
));
}
The name of the model is TPembelian and here is the relation:
public function relations()
{
return array(
'supplier' => array(self::BELONGS_TO, 'MSupplier', 'kode_supplier'),
'tPembelianDetails' => array(self::HAS_MANY, 'TPembelianDetail', 'kode_pembelian'),
);
}
In a controller, I wrote these lines of codes to just simply print out each attributes of CActiveDataProvider:
$model = new TPembelian('search');
$dataProvider = $model->report();
foreach ($dataProvider->getData() as $data) {
echo "<pre>".print_r($data->attributes, 1)."</pre>";
}
the problem is, it only prints out the attributes from TPembelian model (which use alias "p"). Why are other attributes (with other alias beside "p") not printed?
I have searched for a while and it appears that CActiveDataProvider not returning one long query, but instead it returns many query with HAS_MANY relation. Someone said to use "together" and set it to TRUE (I wrote it already in the code above) to make it returns one long query, but it's still not working. Can anybody please help me?
Note:
in the first code, m_supplier, t_pembelian_detail, and m_bahan_baku are tables, not models
I try to execute this query in my CompanyRepository
$qb = $this->_em->createQueryBuilder();
$qb->select(array('c', 'ld'))
->from('Model\Entity\Company', 'c')
->leftJoin('c.legaldetails', 'ld', \Doctrine\ORM\Query\Expr\Join::ON, 'c.companyid=ld.companyid');
$query = $qb->getQuery();
echo($query->getSQL());
When I try to do it I having error:
Fatal error: Uncaught exception 'Doctrine\ORM\Query\QueryException' with message '[Syntax Error] line 0, col 69: Error: Expected end of string, got 'ON'' in /home/raccoon/web/freetopay.dev/www/class/new/library/Doctrine/ORM/Query/QueryException.php on line 42
These are my models:
<?php
namespace Model\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Company
*
* #ORM\Table(name="Company")
* #ORM\Entity(repositoryClass="\Model\Repository\CompanyRepository")
*/
class Company
{
/**
* #var integer $companyid
*
* #ORM\Column(name="CompanyID", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $companyid;
/**
* #var \Model\Entity\LegalDetails $legaldetails
*
* #ORM\OneToOne(targetEntity="\Model\Entity\Legaldetails", mappedBy="companyid")
*/
private $legaldetails;
//other fields
public function __construct()
{
$this->legaldetails = new ArrayCollection();
}
//setters and getters
and legaldetails entity:
<?php
namespace Model\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Legaldetails
*
* #ORM\Table(name="LegalDetails")
* #ORM\Entity
*/
class Legaldetails
{
/**
* #var integer $legalid
*
* #ORM\Column(name="LegalID", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $legalid;
/**
* #var \Model\Entity\Company $company
*
* #ORM\Column(name="CompanyID", type="integer", nullable=false)
* #ORM\OneToOne(targetEntity="\Model\Entity\Company", inversedBy="companyid")
* #ORM\JoinColumn(name="companyid", referencedColumnName="companyid")
*/
private $company;
What is wrong?
For those who came here with the question about "Expected end of string, got 'ON'", but could not find the right answer, as I couldn't (well, there is an answer, but not exactly about QueryBuilder). In general, yes, you don't need to specify the joining columns. But what if you need to add extra filtering. For example, I was looking to add an extra condition (to allow nulls in join).
The problem here is that even though the constant Join::ON exists (and comments in Join expression mention it as well), there is no ON in DQL. Instead, one should use WITH (Join::WITH).
Here is my usage example:
$qb->leftJoin('p.metadata', 'm', Join::WITH, "IFNULL(m.name, '') = 'email'");
P.S. Predicting questions about IFNULL() - it is a Benjamin Eberlei's Doctrine extension.
There's a pretty clear explanation about how JOIN's work with DQL here:
With DQL when you write a join, it can be a filtering join (similar to the concept of join in SQL used for limiting or aggregating results) or a fetch join (used to fetch related records and include them in the result of the main query). When you include fields from the joined entity in the SELECT clause you get a fetch join
this should be enough to get what you want (info about all companies with legal info loaded):
$query = $em->createQuery('SELECT c, ld FROM \Model\Entity\Company c JOIN c.legaldetails ld');
$companies = $query->getResult(); // array of Company objects with the legaldetails association loaded
EDIT:
i used a regular join in my query, so companies with no legal info won't be returned in the query. if you want ALL companies even though they have no legal info loaded you should try with the left join as you were doing
We both thought in terms of SQL. But in DQL WITH is used instead of ON. example
Edit:
If you know SQL, why you don't use query such as:
$query = $this->getEntityManager()->createQuery('
SELECT t...
');
Put there the SQL that you think should be there, check it. If it works - the problem is in Doctrine code, if not - the error is in SQL/DQL
I'm considering using Grails for my current project. I have a couple of requirements that I'm hoping I can do in Grails.
First, I have the following database table:
TagType
---------
tag_type_id
tag_type
Sample Data: TagType
--------------------
1,title
2,author
Based on that data, I need to generate a data entry form like this which
will save its data to another table.
Tile _ _ _ _ _ _ _ _ _ _ _
Author _ _ _ _ _ _ _ _ _ _ _
save cancel
Can I do that in Grails? Can you point me in the right direction?
Thanks!
More Details
I'm building a digital library system that supports OIA-PMH which is a standard for sharing metadata about documents. The standard states that every element is optional and repeatable. To support this requirement I have the following database design.
I need to generate the user GUI (data entry form) based primarily on the contents
of the TagType Table (see above). The data from the form then get's saved to
the Tags (if the tag is new) and Item_Tags tables.
Items
---------
item_id
last_update
Tags
--------
tag_id
tag_type_id
tag
TagType
---------
tag_type_id
tag_type
Item_tags
---------
item_id
tag_id
Sample Data: Items
------------------
1,2009-06-15
Sample Data: TagType
--------------------
1,title
2,author
Sample Data: Tags
------------------
1,1,The Definitive Guide to Grails
2,2,Graeme Rocher
3,2, Jeff Brown
Sample Data: Item_tags
-----------------------
1,1
1,2
1,3
I am not completely sure what you are asking here in regards to "save its data to another table", but here are some thoughts.
For the table you have, the domain class you'd need is the following:
class Tag {
String type
}
ID field will get generated for you automatically when you create the scaffolding.
Please add more information to your question if this is insufficient.
I'm really liking grails. When I first started playing with it a couple of weeks ago, I didn't realize that it's a full fledged language. In fact it's more than that. It's a complete web stack with a web server and a database included. Anyway, the short answer to my question is yes. You might even say yes, of course! Here's the code for the taglib I created:
import org.maflt.flashlit.pojo.Item
import org.maflt.flashlit.pojo.ItemTag
import org.maflt.flashlit.pojo.Metacollection
import org.maflt.flashlit.pojo.SetTagtype
import org.maflt.flashlit.pojo.Tag
import org.maflt.flashlit.pojo.Tagtype
/**
* #return Input form fields for all fields in the given Collection's Metadataset. Does not return ItemTags where TagType is not in the Metadataset.
*
* In Hibernate, the
*
* "from ItemTag b, Tag a where b.tag= a"
*
* query is a cross-join. The result of this query is a list of Object arrays where the first item is an ItemTag instance and the second is a Tag instance.
*
* You have to use e.g.
*
* (ItemTag) theTags2[0][0]
*
* to access the first ItemTag instance.
* (http://stackoverflow.com/questions/1093918/findall-not-returning-correct-object-type)
**/
class AutoFormTagLib {
def autoForm = {attrs, body ->
//def masterList = Class.forName(params.attrs.masterClass,false,Thread.currentThread().contextClassLoader).get(params.attrs.masterId)
def theItem = Item.get(attrs.itemId)
def theCollection = Metacollection.get(attrs.collectionId)
def masterList = theCollection.metadataSet.setTagtypes
def theParams = null
def theTags = null
def itemTag = null
def tag = null
masterList.each {
theParams = [attrs.itemId.toLong(),it.tagtype.id]
theTags = ItemTag.findAll("from ItemTag d, Item c, Tag b, Tagtype a where d.item = c and d.tag = b and b.tagtype = a and c.id=? and a.id=?",theParams)
for (int i=0;i<it.maxEntries;i++) {
out << "<tr>\n"
out << " <td>${it.tagtype.tagtype}</td>\n"
out << " <td>\n"
if (theTags[i]) {
itemTag = (ItemTag) theTags[i][0]
//item = (Item) theTags[i][1]
tag = (Tag) theTags[i][2]
//itemTag = (Tagtype) theTags[i][3]
out << " <input name='${it.tagtype.tagtype}_${i}_${itemTag.id}' value='${tag.tag}' />\n";
}
else
out << " <input name='${it.tagtype.tagtype}_${i}' />\n";
out << " </td>\n"
out << "</tr>\n"
}
}
}
}