Is it possible to setup an EAV structure on PHP ActiveRecord? - entity-attribute-value

What is the best way to link tables in an EAV table structure in PHP ActiveRecord so I can retrieve the entity and all of its attributes/values?
The table structure is something like.
person (entity)
personAttributes (attributes)
personAttributeVarchar (attribute values)
personAttributeText (attribute values)
personAttributeInt (attribute values)
I found this example using a Ruby active record with EAV pattern. Can this be replicated using php active record?
https://github.com/kostyantyn/example_active_record_as_eav/tree/master/app/models

Is that Magento I smell? I hope not. If it is, well, Magento has its own way of mapping EAV and you don't have to reinvent its square wheels. It has mechanisms in place to do what you're trying to do.
If this is something you have control over: You don't want to have separate tables by type. That is a bad idea. There should be a single EAV table per entity, with entity, attribute, and value columns. For 99%
of use-cases, attribute and value can be string columns (PDO returns all column values as string). If you want to go type-crazy (3D EAV) you can enforce attribute as an enum, or foreign key to an entity-specific attributes table.
For the active record class, make an associative $attributes array property, and during save() perform an atomic prune-and-apply (delete all not present in the array, insert-or-replace all values that are present). If you've chosen the (simpler) string attribute route, give your class ArrayAccess that modifies $attributes for added fluency. You can additionally optimize saving by keeping track of whether modifications were made with a bool[] $attributeDiff property.

Related

EAV implementation on SIlverStripe ORM with polymorphic relations

I need to implement EAV and I'm hitched on polymorphic relation.
For example models are:
ProductPage.
Attribute.
AttrValDecimal.
AttrValBool.
AttrValOtherType
How to create relations attribute-value and product-value correctly?
Every attribute can be one of few types: decimal, boolean, item from varchar list, few items from varchar list, etc...
so relations with value must be polymorphic.
I have already read this part of documentation
https://docs.silverstripe.org/en/3/developer_guides/model/relations/#polymorphic-has-one
but still cant sort out how to implement EAV.
I'd to it the other way: have a has_one relation from the value objects back to attribute. Then add a Type enum to Attribute.
Your value tables will technically allow multiple values per attribute, but perhaps that's a feature you need?
The other, in retrospect probably better, way to handle this wood be to make BooleanAttribute a subclass of Attribute and let SilverStripe's multi-table inheritance do Bebe work for you.
You'll have to write your getters for value manually, and figure out which table to join to, but polymorphic has one isn't going to be any magic fix there - it's pretty simple.
Bigger picture I'd also challenge whether EAV is really what you need - it's going to create some really big queries and not be very good for searching. If searching doesn't matter and all need is flexible properties, maybe a JSON payload would be better?

Enum types in database schema

This might be sort of a basic db question, but I'm more used to working with objects rather than tables. Let's say I have an object 'Movie' with property 'genre'. Genre should be restricted by using enumerated types (eg. the only valid genres are Horror, Action, Comedy, Drama). How should this translate to a db schema?
I could put a 'genre' column in the Movies table and rely on checking inputs to ensure that a 'genre' assignment is valid?
Or, I could include a Genres table with pre-filled rows, and then in the Movies table include a column with a foreign key to the Genres table?
I'm leaning towards the first option, but are there pitfalls/etc. that I'm not considering?
I lean toward using the lookup table, your second option. The reason I prefer this is that I can add a new genre simply by adding a row to the Genres table. There would be no need to modify code or to modify the enum definition in the schema.
See also my answer to How to handle enumerations without enum fields in a database?
Here is a useful heuristic: Do you treat all values the same from the client code?
If you do, then just use the lookup table. Even if you don't envision adding new values1 now, requirements tend to change as the time marches on, and the lookup table will allow you to do that without changing the client code. Your case seems to fall into that category.
If you don't, then enum is likely more appropriate - the "knowledge" about each distinct value is contained in your client code anyway, so there is nothing useful left to store in the database.
The gray zone is if you do a little bit of both. E.g. you need to treat values in special ways, but there is still some additional field (associated to each value) that you can treat generically (e.g. just display it to the user). Or you need to treat just some values in special ways. In cases like these, I'd lean towards the lookup table.
1 Or deleting or modifying old values.

How to model a mutually exclusive relationship in SQL Server

I have to add functionality to an existing application and I've run into a data situation that I'm not sure how to model. I am being restricted to the creation of new tables and code. If I need to alter the existing structure I think my client may reject the proposal.. although if its the only way to get it right this is what I will have to do.
I have an Item table that can me link to any number of tables, and these tables may increase over time. The Item can only me linked to one other table, but the record in the other table may have many items linked to it.
Examples of the tables/entities being linked to are Person, Vehicle, Building, Office. These are all separate tables.
Example of Items are Pen, Stapler, Cushion, Tyre, A4 Paper, Plastic Bag, Poster, Decoration"
For instance a Poster may be allocated to a Person or Office or Building. In the future if they add a Conference Room table it may also be added to that.
My intital thoughts are:
Item
{
ID,
Name
}
LinkedItem
{
ItemID,
LinkedToTableName,
LinkedToID
}
The LinkedToTableName field will then allow me to identify the correct table to link to in my code.
I'm not overly happy with this solution, but I can't quite think of anything else. Please help! :)
Thanks!
It is not a good practice to store table names as column values. This is a bad hack.
There are two standard ways of doing what you are trying to do. The first is called single-table inheritance. This is easily understood by ORM tools but trades off some normalization. The idea is, that all of these entities - Person, Vehicle, whatever - are stored in the same table, often with several unused columns per entry, along with a discriminator field that identifies what type the entity is.
The discriminator field is usually an integer type, that is mapped to some enumeration in your code. It may also be a foreign key to some lookup table in your database, identifying which numbers correspond to which types (not table names, just descriptions).
The other way to do this is multiple-table inheritance, which is better for your database but not as easy to map in code. You do this by having a base table which defines some common properties of all the objects - perhaps just an ID and a name - and all of your "specific" tables (Person etc.) use the base ID as a unique foreign key (usually also the primary key).
In the first case, the exclusivity is implicit, since all entities are in one table. In the second case, the relationship is between the Item and the base entity ID, which also guarantees uniqueness.
Note that with multiple-table inheritance, you have a different problem - you can't guarantee that a base ID is used by exactly one inheritance table. It could be used by several, or not used at all. That is why multiple-table inheritance schemes usually also have a discriminator column, to identify which table is "expected." Again, this discriminator doesn't hold a table name, it holds a lookup value which the consumer may (or may not) use to determine which other table to join to.
Multiple-table inheritance is a closer match to your current schema, so I would recommend going with that unless you need to use this with Linq to SQL or a similar ORM.
See here for a good detailed tutorial: Implementing Table Inheritance in SQL Server.
Find something common to Person, Vehicle, Building, Office. For the lack of a better term I have used Entity. Then implement super-type/sub-type relationship between the Entity and its sub-types. Note that the EntityID is a PK and a FK in all sub-type tables. Now, you can link the Item table to the Entity (owner).
In this model, one item can belong to only one Entity; one Entity can have (own) many items.
your link table is ok.
the trouble you will have is that you will need to generate dynamic sql at runtime. parameterized sql does not typically allow the objects inthe FROM list to be parameters.
i fyou want to avoid this, you may be able to denormalize a little - say by creating a table to hold the id (assuming the ids are unique across the other tables) and the type_id representing which table is the source, and a generated description - e.g. the name value from the inital record.
you would trigger the creation of this denormalized list when the base info is modified, and you could use that for generalized queries - and then resort to your dynamic queries when needed at runtime.

Separate table for Value Objects on NHibernate

I'm new to DDD and NHibernate.
In my current project, I have an entity Person, that contains a value object, let's say Address. Today, this is fine. But maybe one day I will have a requirement that my value object (in this case Address), will have to become an entity.
Before trying to model this on a DDD-way, in a more data-centric approach, I had a table Person, with an Id, and another table Address, whose PK was actually an FK, it was the Id of a Person (ie, a one-to-one relationship).
I've been reading that when I map a Value Object as a Component, its value will get mapped as columns on my Entity table (so, I would not have the one-to-one relationship).
My idea was that, when needed, I would simply add a surrogate key to my Address table, and then it becomes an Entity.
How should I design this using NHibernate? Should I already make my Address object an Entity?
Sorry, I don't even know if my questions are clear, I'm really lost here.
In the system we are building, we put Value-Objects in separate tables. As far as I know, NHibernate requires that an id must added to the object, but we ignore this and treat the object as a Value-Object in the system. As you probably know, a Value-Object is an object that you don't need to track, so we simply overlook the id in the object. This makes us freer to model the database the way we want and model the domain model the way we want.
You can Join and make it a Component allowing nHibernate to map it as a proper value object instead of an entity.
This way you won't need any virtual properties nor an empty protected ctor (it can be private).
Join("PROPOSAL_PRODUCT", product =>
{
product.Schema(IsaSchema.PROPOSALOWN);
product.KeyColumn("PROPOSAL_ID");
product.Component(Reveal.Member<Proposal, Product>("_product"), proposalProduct =>
{
proposalProduct.Map...
});
});

NHibernate - how to enforce uniquenes?

My scenario is as follows:
I have some objects (Messages) that can be tagged
So I have a Tag entity and many-to-many relationship
The above is done and working
Now, when tagging, I'd like to save new tags only if they don't exist (where existence is checked by tag title)
if the tag already exists, I'd like it to be recognized and attached to my object instead of a new one
What is the easiest/cleanest way to do it?
BTW, for some reasons I'd like to use artificial primary key (numeric Id) for my Tag entity.
Thanks!
You have a many-to-many relationship that you can express in your business classes and map with NHibernate. The structure of the linking table that resolves the many-to-many relationship will prevent an object from being linked to the same tag more than once.
The only way to enforce the rule in your question is through code. The sequence of tasks would be something like:
Parse user entered tag list into individual tags
Loop through tags ...
a. If a tag exists then add it to the object's tags collection
b. Else create a new tag and add it to the object's tag collection
Persist object
You will need to add logic to look for existing tags taking into account spelling mistakes, capitalization, and alternate usage. For example you don't want to have tags that mean they same thing but do are not equal strings, such as "ASPNET" or "ASP.NET" or "asp.net". The quality of your tag list will depend on how robust the code that checks for existing tags is.
Just to clarify - a Tag can be pinned on many Objects, and an Object can have many Tags. That's what a many-to-many relationship means to me. Is that how you mean it?
When you do this in SQL, you have tables named TAG and OBJECT and a join table named TAG_OBJECT that contains two columns, one for each primary key in the other tables. The primary key in the TAG_OBJECT join table is the pair (TAG_ID, OBJECT_ID). That guarantees a unique pairing for each row.
If you're using Hibernate, you just add a list or collection of Objects as a private data member to your Tag class, and a list or collection of Tags as a private data member to your Object class.
I think Hibernate will handle your "only if it doesn't exist", as long as you write a good method to determine "deep equality" between two instances of Tag.
You should also add a unique constraint to the tag title attribute. Here's an example that doesn't quite fit your needs, because it's Java and XML, but perhaps that hint will be enough to tell you where to look for NHibernate:
<element column="serialNumber" type="long" not-null="true" unique="true"/>
For your case, the column will be the tag title, type is string, and the other flags remain as they are in the example.