Zend DB relationships - zend-framework

I am creating an application in zend framework. Now i am stuck in the Zend table relationships.
I have 2 tables. I have set the primary key and the corresponding references in other tables.
Now i want to join the two tables using the relationships (not with the join functions). Is it possible in zend?
the tables structures are like the one below
Schemetable
scheme_id primary key
Scheme_name
Scheme_Desc
Ratestable
rate_id
Scheme_id *foreign key ref scheme_id*
rates:
Time periods:
There is an one to many relation b/w the scheme and rates
I have done some coding in the model classes
Scheme.php
class Scheme extends Zend_Db_Table_Abstract {
protected $_name = 'schemetable';
protected $_dependentTables = array('rates');
}
Rates.php
class Rates extends Zend_Db_Table_Abstract {
protected $_name = 'ratetable';
protected $_referenceMap = array(
'Scheme' => array(
'columns' => array('scheme_id'),
'refColumns' => array('scheme_id'),
'refTableClass' => 'Scheme',
),
);
}
How can i fetch every scheme and their corresponding rates?
Thanks in advance.

Please,
see the DOCS:
http://framework.zend.com/manual/en/zend.db.table.relationships.html
Fetching a Dependent Rowset
If you have a Row object as the result
of a query on a parent table, you can
fetch rows from dependent tables that
reference the current row. Use the
method:
$row->findDependentRowset($table);
Example #4 Fetching Dependent Rowsets
using the Magic Method
This example shows finding dependent
Rowsets equivalent to those in the
previous examples. In this case, the
application uses the magic method
invocation instead of specifying the
table and rule as strings.
$accountsTable = new Accounts();
$accountsRowset = $accountsTable->find(1234);
$user1234 = $accountsRowset->current();
// Use the default reference rule
$bugsReportedBy = $user1234->findBugs();
// Specify the reference rule
$bugsAssignedTo = $user1234->findBugsByEngineer();
Fetching a parent row
If you have a Row object as the result
of a query on a dependent table, you
can fetch the row in the parent to
which the dependent row refers. Use
the method:
$row->findParentRow($table);
This example shows finding parent Rows
equivalent to those in the previous
examples. In this case, the
application uses the magic method
invocation instead of specifying the
table and rule as strings.
$bugsTable = new Bugs();
$bugsRowset = $bugsTable->fetchAll(array('bug_status = ?', 'NEW'));
$bug1 = $bugsRowset->current();
// Use the default reference rule
$reporter = $bug1->findParentAccounts();
// Specify the reference rule
$engineer = $bug1->findParentAccountsByEngineer();

Related

How to fetch MULTI-LEVELS of related tables in EntityFramework after an Insert?

I have a typical 1-M-1 relationship; to keep it simple, lets deal with 3 tables only, but my real problem is more complex.
UsersTbl --< UserMenusTbl >-- MenusRefTbl
The MenusRefTbl is a reference table, which is pretty much static. To create a new user, I load up data into a newUser Parent Entity (class UsersTbl), and its child navigation property (class UsersMenuTbl).
Then I call
var savedUserEntity = dbCtx.UsersTbl.Add(newUser);
int rowsAffected = dbCtx.SaveChanges();
This inserts data in both Parent and Child table (UsersTbl, UserMenusTbl), and generates any ##identity primary/foreign keys in both tables automatically; In effect, the LHS variable savedUserEntity is now refreshed to contain the auto-generated identities.
However, the navigation property for the 3rd table (MenusRefTbl) remains null;
For example,
savedUserEntity.UserMenusTbl.MenusRefTbl = null;
How do I fetch the 3rd TABLE data into my object savedUserEntity ?
I've seen a few methods like .Reload(), .LoadAsync() but they don't seem to work with navigation properties (multi-levels of related tables), or apply in my case.
So am I stuck with re-issuing a new query from scratch using a new context?
What i have done using the same context:
var savedUserEntity = dbCtx.UsersTbl.Add(newUser);
int rowsAffected = dbCtx.SaveChanges();
rtnUserEntity = dbCtx.UsersTbl
.Include(um => um.UserMenusTbl.Select(m => m.MenusRefTbl))
.Where(u => u.userID == savedUserEntity.userID) //identity after Save
.Single(); //rtn single record

Joining datasources by name in AX 2012 form

I'm trying to join multiple datasources in a grid I created.
The grid is in CaseDetail form and it uses same tables as some other groups on it.
Therefore I have to use joins based on datasources names and not on tables names.
There is InventTable(InventTableComplaints) - parent and EcoResProductTranslation(EcoResProductTranslationComplaints) - child.
What I'm trying to do is to add this code to the child datasource:
public void executeQuery()
{
QueryBuildDataSource qbdsIT, qbdsERPTC;
qbdsIT = InventTableComplaint_DS.queryBuildDataSource();
qbdsERPTC = qbdsIT.addDataSource(tableNum(EcoResProductTranslation), "EcoResProductTranslationComplaint");
qbdsERPTC.addLink(fieldNum(InventTable, Product), fieldNum(EcoResProductTranslation, Product));
qbdsERPTC.joinMode( JoinMode::OuterJoin );
qbdsERPTC.fetchMode( QueryFetchMode::One2One );
super();
}
But it doesn't work.
Is it possible?
You do not define the table relations in the executeQuery method, do so in the init method instead which is executed exactly once. If you defined the datasource in the form (using InventTableComplaint as JoinSource and with OuterJoin as JoinMode), you do not need to do it in init method either, but you may need to define the link if not provided as table relations:
public void init()
{
qbdsIT = InventTableComplaint_DS.queryBuildDataSource();
qbdsERPTC = EcoResProductTranslationComplaint_ds.queryBuildDataSource();
qbdsERPTC.clearLinks();
qbdsERPTC.addLink(fieldNum(InventTable, Product), fieldNum(EcoResProductTranslation, Product));
super();
}
Beware that more than one record of may exist of EcoResProductTranslation for each InventTable (on for each language), so you may end out with "duplicates" of InventTable in the grid.

Can TableGateway Use Multiple Tables Zend Framework 2

In my module.php file, I want to pass multiple table names via TableGateway class in Zend Framework but I cannot find any documentation on it, other than it being limited to one table. The phpdoc for this (TableGateway) class says an array can be passed but again, I am not sure if it accepts more than one table.
for example in Module.php:
'Application\Model\LoginModel' => function($sm) {
$table_gateway = $sm->get('LoginService');
$table = new LoginModel($table_gateway);
return $table;
},
'LoginService' => function($sm) {
$db_adapter = $sm->get('Zend\Db\Adapter\Adapter');
$result_set_prototype = new ResultSet();
$result_set_prototype->setArrayObjectPrototype(new Login());
return new TableGateway(array('admins', 'members'), $db_adapter, null, $result_set_prototype);
}
Is it possible to do this and have multiple tables referenced or bound like this, or is it only designed to allow one table for each instance?
No it is not. Table Gateway object is intended to provide an object that represents a table in a database. Array can be passed to the constructor, but if you pass it, you will get InvalidArgumentException. Please check this code
https://github.com/zendframework/zend-db/blob/release-2.8.2/src/TableGateway/TableGateway.php#L34,L35
Please look at again TableGateway purposed on documentation here
https://framework.zend.com/manual/2.4/en/modules/zend.db.table-gateway.html

Best Way to convert one Edmx Entity to one Business entity

I am developing one application in which data is access from edmx entities and from that we have to fill each business entity after retriving data from edmx entity like:-
var tblproducts = tblproductsData
.Select(t => new tblProduct()
{
CategoryID = t.CategoryID,
Description = t.Description,
ID = t.ID,
Image = t.Image,
InsDt = t.InsDt,
Price = t.Price,
Quantity = t.Quantity,
Status = t.Status,
Title = t.Title,
tblCategory = new EFDbFirst.Models.tblCategory()
{
ID = t.tblCategory.ID,
status = t.tblStatus.StatusID,
Title_Category = t.tblCategory.Title_Category
},
tblStatu = new EFDbFirst.Models.tblStatu()
{
StatusDescription = t.tblStatus.StatusDescription
,
StatusID = t.tblStatus.StatusID
}
});
I am fadeup with this because everytime i have to convert one to another while getting data and setting data in db,
Is there any good way to create some common mehod which takes one anonymous type and converts it to another anonymous type.
Thanks in Advance
Your example isn't that clear.
First of all, EF doesn't work with anonymous types inside itself, it works with the EF types you have defined either using edmx file or code first. You can however create anonymous types yourself by defining an Select statement.
E.g:
var products = context.tblProductsData
.Select(r => new { Description = r.Description }); //new without typename is an
//anonymous object
The tblProduct, tblCategory and tblStatu objects, are they EF types? If so, you don't need to write a Select, EF will generate objects for you when you execute it.
E.g:
var products = context.tblProductsData.ToList();
This will automatically generate tblProduct objects for you. When you try to navigate to tblProduct.tblCategory or tblProduct.tblStatu, lazy loading will retrieve them for you. If you want to explicit load them during first query (eager-loading) use the Include function.
E.g:
var products = context.tblProductsData.Include(r => r.tblCategory)
.Include(r => r.tblStatu).ToList();
However if tblProducts, tblCategory and tblStatu is business objects and NOT EF types, there isn't any other way to do this, you have to explicit create them in a Select statement.

zend relationships with select

I am new to zend. I have been asked to redevelop a website that was once written in plain PHP and put it into the zend framework.
I am having a lot of trouble with database relationships, I cant seem to get my head round defining and querying relationships.
I would like to find a Category. From that Category I would like to be able to find all the CategoryInfo associated with it, and be able to query/sort/limit that dataset.
Here are my models.
Categorys.php
<?php
class Default_Model_Categorys extends Zend_Db_Table_Abstract
{
protected $_name = 'Categorys';
protected $_primary = 'id';
protected $_dependentTables = array('Default_Model_CategoryInfo');
}
?>
CategoryInfo.php
<?php
class Default_Model_CategoryInfo extends Zend_Db_Table_Abstract
{
protected $_name = 'Category_Info';
protected $_primary = 'id';
protected $_referenceMap = array(
'Categorys' => array(
'columns' => array('cat_id'),
'refTableClass' => 'Default_Model_Categorys',
'refColumns' => array('id')
)
);
}
?>
CategoryController.php
<?php
class CategorysController extends Zend_Controller_Action
{
public function indexAction()
{
/*
this should redirect to all games
*/
return $this->_forward("index", "games");
}
public function categoryAction()
{
/*
shows a specific category
*/
$id = (int) $this->_request->getParam('id');
$category = new Default_Model_Categorys();
$this->view->category = $category->fetchRow(
$category->select()->where('id = ?', $id)
);
$categoryInfo = $this->view->category->findDependentRowset('Default_Model_CategoryInfo');
}
}
Firstly... am I doing anything wrong?
Secondly... how do I go about querying the dependent rowset?
First, if you're searching for a category by its primary key, it's simpler to use the find() method:
$id = (int) $this->_request->getParam('id');
$category = new Default_Model_Categorys();
$this->view->category = $category->find($id)->current();
Second, to restrict or sort dependent Category_Info rows, you can use a Zend_Db_Table_Select object as an optional parameter of findDependentRowset(). Here's an example:
$select = $category->select()->where("info_type = 'PRICE'")
->order("info_date")
->limit(3);
$categoryInfo = $this->view->category->findDependentRowset(
'Default_Model_CategoryInfo', null, $select);
Notice you can use any table object to create that select object. Since the "FROM" clause for that select will be set by the findDependentRowset() method, you just add other clauses and then pass it in.
PS: You don't need to declare $_dependentTables at all, unless you're going to use cascading update or cascading delete via PHP code. I recommend strongly against doing that -- it's far more efficient to let the RDBMS handle those cascading operations.
Likewise you should never have to declare $_primary if your database tables actually declare primary key constraints. Zend_Db_Table_Abstract knows how to inspect metadata to get the primary key column(s).
Everything looks correctly to me. You don't query a dependent rowset. It is a query itself and it returns a result set. Basically what it is doing is pulling all records related to the current row you are working with as defined by $_referenceMap. Once you execute findDependentRowset(), you can foreach over the results which will give you instances of Zend_Db_Table_Row. From there you can display the related data as needed.
Personally I don't use Zend_Db Relationships. It is much easier to just make a second model method to query what I need. Also, Zend_Db Relationships do not support where clauses, so just making a second query is much more flexible than relationships.