In database I have two types of tables [based on their name]
Example:
1. smw_di_... => [semantic mediawiki data item => as I understood]
2. smw_fpt_... => [??]
And what is the key s_id
Does someone know?
It's important to me to understand the logic, because no books are available, no documentation...
FPT - Fixed Property Table
Fixed Properties are properties that are user defined but intensively used in the wiki
extensions/SemanticMediaWiki/src/SQLStore/PropertyTableInfoFetcher.php
private $fixedSpecialProperties = array(
// property declarations
'_TYPE', '_UNIT', '_CONV', '_PVAL', '_LIST', '_SERV',
// query statistics (very frequently used)
'_ASK', '_ASKDE', '_ASKSI', '_ASKFO', '_ASKST', '_ASKDU',
// subproperties, classes, and instances
'_SUBP', '_SUBC', '_INST',
// redirects
'_REDI',
// has sub object
'_SOBJ',
// vocabulary import and URI assignments
'_IMPO', '_URI',
// Concepts
'_CONC'
);
s_id => pointer [foreign key to smw_object_ids smw_id]
p_id => property id if it's not fixed DI
Related
Since this mornong i am facing a very big problem. I am using CodeIgniter to develop a website, and GAS ORM for the database.
I have basically two tables. One named "pool", and one named "partners". I am having two associations between these two tables, so I have two foreign keys in my table Partners referencing the table pool.
Pool(#id:integer, name:varchar)
Partners(#id:integer, associated_pool_id=>Pool, futur_associated_pool_id=>Pool).
As I have two references to the same table, I can't name the foreign keys "pool_id". So in my relationships with Gas ORM, I have to specify the names of the columns. I do it, but it doesn't work...
Here is what I do:
class Partner extends ORM {
public $primary_key = 'id';
public $foreign_key = array('\\Model\\Pool' => 'associated_pool_id', '\\Model\\Pool' => 'future_associated_pool_id');
function _init()
{
// Relationship definition
self::$relationships = array(
'associated_pool' => ORM::belongs_to('\\Model\\Pool'),
'future_association_pool' => ORM::belongs_to('\\Model\\Pool'),
);
self::$fields = array(
'id' => ORM::field('auto[11]'),
'name' => ORM::field('char[255]'),
'associated_pool_id' => ORM::field('int[11]'),
'future_associated_pool_id' => ORM::field('int[11]')
);
}
and in my Pool class :
class Pool extends ORM {
public $primary_key = 'id';
function _init()
{
// Relationship definition
self::$relationships = array(
'associated_partner' => ORM::has_many('\\Model\\Partner'),
'future_associated_partner' => ORM::has_many('\\Model\\Partner'),
);
self::$fields = array(
'id' => ORM::field('auto[11]'),
'name' => ORM::field('char[50]'),
);
}
I have a test controller testing if everything is okay:
class Welcome extends CI_Controller {
public function index()
{
$pool = \Model\Pool::find(1);
echo $pool->name;
$partners = $pool->associated_partner();
var_dump($partners);
}
But I have an error saying:
Error Number: 1054
Champ 'partner.pool_id' inconnu dans where clause
SELECT * FROM partner WHERE partner.pool_id IN (1)
I don't know how to specify to Gas ORM that it shouldn't take "pool_id" but "associated_pool_id"....
Thank you for your help!!!!!!!!!!!!
I don't know, if this topic is still up to date and interesting to some of you, but in general, I had the exact same problem.
I decided Gas ORM to be my mapper in combination with CodeIgniter. As my database structure was given and it was not following the table_pk convention of Gas, I had to define a foreign key by myself which shall refer to my custom database foreign key. However, the definition of it had no impact on anything. Like your error above, the mapper was not able to build the right SQL-statement. The statement looked similar to yours:
SELECT * FROM partner WHERE partner.pool_id IN (1)
Well, it seems like Gas ignores the self-defined foreign keys and tries to use the default table_pk convention. This means, it takes the table (in your case: pool) and the primary key (id) by merging it with a underscore character.
I figured out, that the constructor of orm.php handles every primary and foreign key defined within the entities. In line 191, the code calls an if clause combined with the empty function of php. As the primary key is defined always and there is no negation in the statement, it skips the inner part of the clause every time. However, the inner part takes care of the self-defined foreign keys.
Long story short, I added a negation (!) in line 191 of orm.php which leads me to the following code:
if ( ! empty($this->primary_key))
{
if ( ! empty($this->foreign_key))
{
// Validate foreign keys for consistency naming convention recognizer
$foreign_key = array();
foreach($this->foreign_key as $namespace => $fk)
{
$foreign_key[strtolower($namespace)] = $fk;
}
$this->foreign_key = $foreign_key;
}
else
{
// If so far we didnt have any keys yet,
// then hopefully someone is really follow Gas convention
// while he define his entity relationship (yes, YOU!)
foreach ($this->meta->get('entities') as $name => $entity)
{
if ($entity['type'] == 'belongs_to')
{
$child_name = $entity['child'];
$child_instance = new $child_name;
$child_table = $child_instance->table;
$child_key = $child_instance->primary_key;
$this->foreign_key[strtolower($child_name)] = $child_table.'_'.$child_key;
}
}
}
}
Well, this little fix helped me out a lot and I hope some of you can take advantage of this hint as well.
This seems very much similar to: EF4.1 multiple nested entity Includes gets NotSupportedException?
But the exception message is different and we are using a newer libraries.
Trying to load an entity graph with 3 levels made of: Accounting Record which contains multiple AccountingOperation(s) which in turn each of them contain multiple AccountingOperationLine(s). The exception below occurs if I want to load the 3 nevigation properties on the 3rd level (1 synthetical and 2 analytical accounts) as shown below.
Code:
var v = dbEntities.Set<AccountingRecord>()
.Include(ar => ar.AccountingRecordOperations.Select(
aro => aro.AccountingRecordOperationLines.Select(arol => arol.AccountingSynthetic)))
.Include(ar => ar.AccountingRecordOperations.Select(
aro => aro.AccountingRecordOperationLines.Select(arol => arol.AccountingAnalytical1)))
.Include(ar => ar.AccountingRecordOperations.Select(
aro => aro.AccountingRecordOperationLines.Select(arol => arol.AccountingAnalytical2)))
.ToList();
Exception
NotSupportedException: All objects in the EntitySet 'DbEntities.Entities' must have unique primary keys.
However, an instance of type '...AccountingSynthetic' and an instance of type '...AccountingRecordOperation' both have the same primary key value, 'EntitySet=Entities;ID=1104'
Something clearly confuses EF since AccountingSynthetic and AccountingRecordOperation don't share the id.
Configuration:
Model first
TPT
MySQL 5.6
MySQl Connector 6.8.3
EF 6.0
Notes:
All entities inherit of Entity.
The synthetic and analytical accounts all of them have a one to many relation to AccountingOperationLines (could this confuse EF?)
The error persist even with this simpler query like:
var v = dbEntities.Set<AccountingRecord>()
.Include(ar => ar.AccountingRecordOperations.Select(aro => aro.AccountingRecordOperationLines.Select(arol => arol.AccountingSynthetic)));
Table.linkedIndex is related to LinkedIndex.ID. The value of the field LinkedIndex.TableName is either Linked1 or Linked2 and defines which of these tables is related to a row in Table.
Now i want to make a dynamical link with Yii models so that i can easily get from a Table row to the corresponding Linked1 or Linked2 row:
Table.linkedID = [LinkedIndex.TableName].ID
Example
Table values:
LinkedIndex values:
Now I should get the row from Linked2 where ID=2:
$model = Table::model()->findByPk(0);
$row = $model->linked;
Model
In the model Table, I tried to make the relation to the table with the name of the value of linkedIndex.TableName:
public function relations()
{
return array(
'linkedIndex' => array(self::HAS_ONE, 'LinkedIndex', array('ID' => 'linkedIndex')),
'linked' => array(
self::HAS_ONE,
'linkedIndex.TableName',
array('ID' => 'linkedID'),
)
)
}
But then I get the error:
include(linkedIndex.TableName.php) [function.include]: failed to open stream: No such file or directory
Is there any way to make a dynamic relation Table.linkedID -> [LinkedIndex.TableName].ID with Yii Models?
Per the Yii docs here:
http://www.yiiframework.com/doc/api/1.1/CActiveRecord#relations-detail
I'd suggest using self::HAS_ONE instead (unless there can be multiple rows in LinkedIndex with the same ID - although from the looks of above, I doubt that's the case).
You can link tables together that have different keys by following the schema:
foreign_key => primary_key
In case you need to specify custom PK->FK association you can define it as array('fk'=>'pk'). For composite keys it will be array('fk_c1'=>'pk_с1','fk_c2'=>'pk_c2').
so in your case:
public function relations(){
return array(
'linkedIndex' => array(self::HAS_ONE, 'LinkedIndex', array('ID' => 'linkedIndex')),
);
}
where LinkedIndex is the class name for the LinkedIndex model (relative to your Table model - i.e. same folder. You could change that, of course) and array('ID' => 'linkedIndex') specifies the relationship as LinkedIndex.ID = Table.linkedIndex.
Edit
Looking at your updated example, I think you're misunderstanding how the relations function works. You're getting the error
include(linkedIndex.TableName.php) [function.include]: failed to open stream: No such file or directory
because you're trying to create another relation here:
'linked' => array(
self::BELONGS_TO,
'linkedIndex.TableName',
array('ID' => 'linkedID'),
)
This part: linkedIndex.TableName refers to a new model class linkedIndex.TableName, so Yii attempts to load that class' file linkedIndex.TableName.php and throws an error since it doesn't exist.
I think what you're looking for is to be able to access the value TableName within the table LinkedIndex, correct? If so, that's accessible from within the Table model via:
$this->linkedIndex->TableName
This is made possible by the relation we set up above. $this refers to the Table model, linkedIndex refers to the LinkedIndex relation we made above, and TableName is an attribute of that LinkedIndex model.
Edit 2
Per your comments, it looks like you're trying to make a more complex relationship. I'll be honest that this isn't really the way you should be using linking tables (ideally you should have a linking table between two tables, not a linking table that says which 3rd table to link to) but I'll try and answer your question as best as possible within Yii.
Ideally, this relationship should be made from within the LinkedIndex model, since that's where the relationship lies.
Since you're using the table name as the linking factor, you'll need to create a way to dynamically pass in the table you want to use after the record is found.
You can use the LinkedIndex model's afterFind function to create the secondary link after the model is created within Yii, and instantiate the new linked model there.
Something like this for your LinkedIndex model:
class LinkedIndex extends CActiveRecord{
public $linked;
public static function model($className = __CLASS__){
return parent::model($className);
}
public function tableName(){
return 'LinkedIndex';
}
public function afterFind(){
$this->linked = new Linked($this->TableName);
parent::afterFind();
}
//...etc.
}
The afterFind instantiates a new Linked model, and passes in the table name to use. That allows us to do something like this from within the Linked model:
class Linked extends CActiveRecord{
private $table_name;
public function __construct($table_name){
$this->table_name = $table_name;
}
public static function model($className = __CLASS__){
return parent::model($className);
}
public function tableName(){
return $this->table_name;
}
//...etc.
}
which is how we dynamically create a class with interchangeable table names. Of course, this fails of the classes need to have separate operations done per-method, but you could check what the table_name is and act accordingly (that's pretty janky, but would work).
All of this would result in being to access a property of the linked table via (from within the Table model):
$this->linkedIndex->linked->foo;
Because the value of LinkedIndex.TableName and Table.linkedID is needed to get the values, I moved the afterFind, suggested by M Sost, directly into the Table-Class and changed its content accordingly. No more need for a virtual model.
class Table extends CActiveRecord {
public $linked; // Needs to be public, to be accessible
// ...etc.
public function afterFind() {
$model = new $this->linkedIndex->TableName;
$this->linked = $model::model()->findByPk( $this->linkedID );
parent::afterFind();
}
// ...
}
Now I get the row from Linked2 where ID=2:
$model = Table::model()->findByPk(0);
$row = $model->linked;
I have two tables:
tags
---
id
name
etc..
tags_synonyms
---
tag_id
syn_id
The syn_id is the synonym tag's id, and the tag_id reflects the "root" tag that will actually be used. The synonyms exist only to provide alternative spelling/etc for tags to reference and find the root tag through. (please correct me if they should be stored in a separate table)
So I created a model Tag in Yii, but I'm not sure how to setup the relationships for it.
What I want to be able to do is do:
$tag->synonyms, and $tag->root to grab all synonyms and the one root tag respectively.
How would I setup the relationships for these two things?
just check this link..to know more about how relationships are made in Yii Framework
http://www.yiiframework.com/doc/blog/1.1/en/post.model#customizing-x-16x-method
Relation should be declared in TagsSynonyms model
public function relations()
{
return array(
'synonymstags' => array(self::BELONGS_TO,'TagsSynonyms','tag_id'),
);
}
Relation should be declared in Tags model
public function relations()
{
return array(
'tags' => array(self::HAS_MANY, 'Tags', 'tag_id'),
);
}
I ended up just adding a linked_to root word column to the tags table and using that to reference the main word from the synonyms.
I looked through the file Mage/Catalog/sql/catalog_setup/install-1.6.0.0.php.
The part of code:
$installer = $this;
/* #var $installer Mage_Catalog_Model_Resource_Setup */
$installer->startSetup();
/**
* Create table 'catalog/product'
*/
$table = $installer->getConnection()
->newTable($installer->getTable('catalog/product'))
->addColumn('entity_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
'identity' => true,
'unsigned' => true,
'nullable' => false,
'primary' => true,
), 'Entity ID')
You can see here catalog_product implementation: $installer->getTable('catalog/product').
But I couldn't find this table in DB.
How does it work then? I always thought that catalog/product = catalog_product.
The following function
getTable('catalog/product')
can be traced back to
app/code/core/Mage/Core/Model/Resource.php
checking the public function getTableName($modelEntity) you will see that the logic treats also resource table names:
<catalog_resource>
<class>Mage_Catalog_Model_Resource</class>
<deprecatedNode>catalog_resource_eav_mysql4</deprecatedNode>
<entities>
<product>
<table>catalog_product_entity</table>
</product>
more resources about this:
Magento ORM: Entity Attribute Value; Part 1 and
Magento Setup Resources from Alan Storm
As is often the case in Magento, configuration is being used. Here's the call stack:
Mage_Core_Model_Resource_Setup::getTable('catalog/product')
Mage_Core_Model_Resource::getTableName('catalog/product');
When a '/' is present in the argument passed to the core/resource class's getTableName method, the configuration DOM is inspected. First the method will resolve the resourceModel node with the following line:
$resourceModel = (string) Mage::getConfig()->getNode()->global->models->{$model}->resourceModel;
Then, the core/resource class calls its getEntity() method, with the resourceModel node passed as the argument. This method simply looks under the resolved (resource) model node for the entity declaration (i.e. tablename):
Mage::getConfig()->getNode()->global->models->{$model}->entities->{$entity};
In the case of catalog/product, the above maps to:
Mage::getConfig()->getNode()->global->models->catalog_resource->entities->product;
If you look in Mage_Catalog's configuration xml, you'll see this borne out. The reason why it is best to access the tablename via configuration is that it is possible to specify table prefix, and using this method will return the correct name.