Sequelize, Many-To-Many On Non-ID Properties - many-to-many

I have one model, Target, which has a property/field called targetName. I have a second model, Operation, with a field verb. Both these models have a primaryKey field named id.
I have a third model, Policy, that is a defined association/join with additional properties; Policy also contains targetName and verb fields. How do I specify in the belongsToMany() for Target and Operation to use the fields above, instead of defaulting to the id field? I know of the through option to specify the actual model. What's in the ellipsis section below?
Target.belongsToMany(Operation, {through: Policy, ...});
and
Operation.belongsToMany(Target, {through: Policy, ...});
Also, do I just specify the two belongsToMany()?

There is no way to do foreign keys pointing to non-primary keys in sequelize. See https://github.com/sequelize/sequelize/issues/2967

Related

What is the best option when naming a pivot table where one of the columns refers to a different model?

I'm using Laravel and Mysql.
I'm trying to come up with a name for my pivot table where one column is a foreign key to the products table and the other column is a foreign key to the users table. I want the table name to be product_point_of_contact. I don't want to call the table product_user as that doesn't really explain what the table does. My columns would be product_id and user_id. I don't want to name the user_id column point_of_contact_id because I don't have a point_of_contacts table.
What is the convention and best option for this? Would you also create a PointOfContact model and extend it to use the User model?
The Laravel convention is:
To determine the table name of the relationship's intermediate table, Eloquent will join the two related model names in alphabetical order. However, you are free to override this convention. You may do so by passing a second argument to the belongsToMany method:
return $this->belongsToMany(Role::class, 'role_user');
In addition to customizing the name of the intermediate table, you may also customize the column names of the keys on the table by passing additional arguments to the belongsToMany method. The third argument is the foreign key name of the model on which you are defining the relationship, while the fourth argument is the foreign key name of the model that you are joining to:
return $this->belongsToMany(Role::class, 'role_user', 'user_id', 'role_id');
So, if your models are Product and User, and you name the intermediate table as product_point_of_contact, and the fk product_id and user_id.
In your User model use:
return $this->belongsToMany(Product::class, 'product_point_of_contact');
In your Product model use:
return $this->belongsToMany(User::class, 'product_point_of_contact');
And you will not need to specify the foreign keys, since these do comply with the convention.
Said that...
What is the convention and best option for this?
IMO, the one you (and your team) can understand, and makes sense in the business logic of your application. Even if you/they read the code or the name of the tables within 6 months.
Would you also create a PointOfContact model and extend it to use the User model?
Not needed, you can use the User model. What I would do here would be to name the relationship with the meaning I want to give. For example:
class Product extends Model
{
/**
* The product point of contact (which is an user).
*/
public function pointOfContact()
{
return $this->belongsToMany(User::class, 'product_point_of_contact');
}
}
product_user will be the best since laravel itself will create the table name in alphabetical order, i advice you use product_user.

How restrict attribute names in entity attribute value?

This pattern allows attaching multiple attributes to one entity. Say that entity has a type which defines a set of attributes. How constraining attributes for MySQL which do not support custom constraints?
Constraining the possible attributes will defeat the purpose of the pattern...
There are 3 ways to do it:
use an enum column for the attribute
add a foreign key to a table with a list of allowed attributes
add a insert/update trigger and do whatever validation you want in it

How to refer to hardcoded values in code from the database?

In the (MySQL) database, I'm storing a view hierarchy, with each row in a table referring to a single view. There are several types of views, but they're stored in the same table.
In the application code, each type of view has its own class. Each row in the database instantiates one of these classes.
How should I refer to these classes from the database, so the application knows which class to use?
I can think of several possibilities:
Just specify the class name directly in the table, but this has the disadvantage of having to change lots of rows if the class name changes (which can be done in a single query if required).
Have a separate table storing class names, and use foreign keys to point to the row storing the correct class name. In this case, I could forgo having an ID field in this lookup table and instead have the class name as the primary key and target foreign key, and rely on a cascading UPDATE if the class name changes?
Are there better options available?
If I understand correctly you want to maintain an association between view-names and class-names.
Your bullets suggests, that there can be more than one view for the same class and both of your suggestions would work. The second bullet has the advantage that you can change the class name with a single update. But that doesn't buy you much, because as soon as more than just a single class-name changes, i.e. when the association itself changes, you need to update more than one row.
You might even create a separate table, holding this association. This would be the model for an n:m relationship, which is too general, so you'd have to place a unique constraint on the view-name. Essentially this will just factor out the concern of associating view-names with class-names and allow you to change this mechanism entirely without having to mess with your tables (except the one holding this association).
But actually I would not store any of this stuff in the database
(I also find it irritating that view-names are stored in the database and not in the application logic). The fact that there are class-names, should be of no concern to your database. This is application logic and it should be handled there. So what you need is a way to instantiate an object when the view-name is known. This looks like a classic factory to me. After all, if a class name changes, it is a change in the application code and life is easier, when all resulting changes lie in the application code as well.

Relational database design

I'm trying to understand entities, tables and foreign keys. I have the following:-
AnObject - I have identified this as an entity type.
ID (Primary Key)
Description
State
DependsOn
Creator
Now State has only two values it can be [Alive, Dead]. However it could possibly have another in the future. It can however only be one or the other but it will likely change between the two.
Question:
Should State be its own entity type? Would it be an entity type or
just a table? Should State have a foreign key to AnObject or vice
versa? EG
State
ID (PK)
Description
AnObject_ID (Foreign Key references AnObject)
Question: The DependsOn attribute of AnObject can have multiple values of other AnObject entity types. Obviously a field cannot have multiple values but I'm not sure how to model this?
The Creator attribute of AnObject also takes up a strict number of values [Fred, Jim, Dean]. Should I have an entity type (table) for a Creator with a foreign key to AnObject ID? So, A Creator can create, 0, 1, m AnObjects but AnObject can only have one creator?
Thanks,
State could just be an enum field, unless you need users to be able to add other State values via a user interface, in which case you could use a lookup table (one-to-many relationship) as you suggested. I don't know what database you're using, but here's some info on the enum type in MySQL: http://dev.mysql.com/doc/refman/5.6/en/enum.html.
If you use a lookup table, then AnObject should have a field called StateID that points to the desired row in the State table.
It sounds like DependsOn is a many-to-many relationship. For that you will need a join table, e.g.:
Table: Dependencies
Primary key (called a "composite key" because it's made up of more than one field):
AnObjectParentID
AnObjectChildID
I've assumed that the dependencies are needed for a parent-child relationship but if that's not the case you might want to name the table or fields differently.
You can add extra tables for enumeration values with a foreign key from AnObject to it. State will probably be best represented as a single field of type varchar not null. You can have the primary key for a table be a varchar field - they don't have to be int type.
This will constrain the values but allow you to use reasonable syntax to query the thing (i.e. WHERE state = 'Alive' (although in this case I think you're prematurely abstracting things - I'd keep it simple and just have a simple bool column IsDead).
DependsOn is a one-way attribute (you presumably can't have A depend on B and also B depend on A). The real issue here is how you're intending to query these items and how many of them there will be. If you want to pull out the whole chain of dependencies at once and the chain is long, you want to avoid doing hundreds of individual queries to do that. What is your use case?

Inaport Lookups can't find target entity - CRM4 Connector

The documentation for inaport states you can just map lookup fields and it will work out what types they are.
I am mapping from CRM 4 to CRM 2011 (using the CRM Connectors), however all my lookups fail with
A lookup value was mapped to account.{field name} but no target entity name was supplied and no default is available.
I have to fall back to adding a custom field, checking if their is a lookup id in the field, and then making a lookup value as per the documentation of guid::entityname using expressions which is painful.
Is this feature working for anyone else? Do i need to set up a child-parent relationship? I only ever add a map for the entity I'm working on.
Inaport will try to work out what the correct entity reference is and default it. For example, if the lookup is the foreign key in a child table, the entity reference will default to the parent.
There are some circumstances where a lookup may reference multiple entity types, and Inaport cannot infer the correct type. For example, and activity "regarding" lookup may reference 12 different entity types.
It could do a better job when a custom lookup is only referencing a single entity type, and a change request has been put into the system.
As you noted, when Inaport does not correctly infer the entity type you can force it by appending "::entityname" to the GUID you are mapping to the lookup field. This is discussed in more detail in the help.
HTH
Regards
David Evans