NHibernate - how to enforce uniquenes? - nhibernate

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.

Related

Class Diagram: In A Composition Relationship Should a Child Class Always Have An ID Field?

I'm having a hard time converting my database tables and foreign keys to a class diagram with classes and associations.
My question is:
"In in a composition relationship, should a child class always should have an ID field?".
In my CD, there are 2 compositor classes: PurchaseItem and PurchaseFinisher, which composite Purchase class. PurchaseItem already comes with an ID field from its table but, PurchaseFinisher doesn't because it is filtered by the id_purchase and id_payment_method foreign keys.
thanks in advance.
This is my DB diagram:
I can't see redundancy in between Purchase or Product, as you said. Could you, please, show me that based on my DB diagram? My tables are well modeled (hope so). My fault is in the classes definition.
In a class diagram, no class requires an id property: each class instance (aka object) has its own identity with or without explicit id property.
In a database, you need of course an explicit id property to uniquely identify the object among others in the database and find it back. By the way, you may annotate such properties with a trailing {id} . UML does not define any semantic for it, but it is in general sufficiently expressive to help database designers.
In the case of composition, the main question is whether a composed object can easily be identified by alternate means. There are several related ORM database techniques, for example:
you can use the owning object’s id together with another property if this is sufficient to identify the element. The two together would make a composite primary key in database.
you can use a unique id to identify the object (surrogate primary key) and use the id of the owning object as foreign key.
For PurchaseItem you have everything that is needed, although the diagram does not tell which of the two approaches you’ll use (e.g is the id unique globally, or unique within the purchase?).
But for PurchaseFinisher it is unclear if you could uniquely identify an occurence. If a payment method can only be used once per purchase, it’s fine as it may be used to identify the object.
If it would be allowed to pay two times the same amount (half of the overall price) in the same currency with the same payment methods, you’d have undistinguishable duplicates. So, some kind of identifier will be needed from the database point of view.

Is it possible to setup an EAV structure on PHP ActiveRecord?

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.

A non-standard many-to-many relationship in NHibernate

I have two tables (Rule and Object) linked through a many-to-many relationship. A Rule may be associated with any number of Objects, or it may be associated with all Objects.
I would normally build this association with a link table where, the Object_ID column would be set to NULL if the associated Rule was to be associated with all Objects. Any value that won't actually reference a real Object will do.
This way, I could write an Select to find all Rules associated with an object like this:
SELECT * FROM Rule JOIN RuleObject_Link on Rule.ID = RuleObject_Link.RuleID WHERE RuleObject_Link.ObjectID = <the object ID> or RuleObject_Link.ObjectID IS NULL
The problem is that I am using NHibernate. I can't find a way to signify "all Objects" in the automated relationship/collection structure.
Is it possible to build a relationship like this using NHibernate's many-to-many relationship?
Or will I have to manually configure the link table and handle the connection myself?
It would be better to add a separate boolean field to Rule signifying that it applies universally to all Object objects (Object is a pretty bad classname by the way).
This really doesn't participate in the relationship mapping, and getting the entire list of rules for an object would require a query rather than being populated automatically from mappings, but I can't think of anything better right now.

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.

Association end is not mapped in ADO entity framework

I am just starting out with ADO.net Entity Framework I have mapped two tables together and receive the following error:
Error 1 Error 11010: Association End 'OperatorAccess' is not mapped. E:\Visual Studio\projects\Brandi II\Brandi II\Hospitals.edmx 390 11 Brandi II
Not sure what it is I am doing wrong.
I believe I can add some more clarity to the issue (learning as I go):
When I look at the Mapping details and look at the association, the column for operatoraccess table (from above) is blank and the drop down only includes field from the linked table.
The Entity Framework designer is terrible - I've had the same problem many times (and your problem too, Craig):
This happens when you have a many-to-one association which is improperly setup. They could very easily fix the designer to make this process simple; but instead, we have to put up with this crap.
To fix:
Click on the association, and go to the mapping details view.
Under association, click on Maps to <tablename>. Choose the table(s) which make up the many side of the relationship (ie. the table(s) which make up the *-side of the association in the designer)
Under Column, choose the table-columns which map to each entity-side Property. You get this error when one of those entries are blank.
I had the exact same problem and this is what I did to fix it.
Make sure you have an Entity Key set in your designer on the tables your making an association with. Also check that StoreGeneratedPattern is set to Identity for that Entity Key.
There's not a lot of information in your question, but, generally speaking, this means that there is an incompletely defined association. It could be that you have tried to map one table with a foreign key to another table, but have not mapped that other table. You can also get this error when you try to do table per type inheritance without carefully following the steps for implementing that feature.
Not sure of the answer, but I've just posted a similar question, which may at least help clarify the issue you are experiencing.
Defining an Entity Framework 1:1 association
I had to go back into the database itself and clarify the foreign key relationship
I had this problem in the case where I was creating both many to 0..1 and 0..1 to 0..1 associations. One entity needed associations to multiple tables, and that entity did not have foreign keys defined for those tables.
I had to do the table mappings step that is given in the accepted answer, but note that it wasn't only for many to many associations; it applied to all the types of associations I added for this entity.
In the Mapping Details view, I had to select the entity with the non-foreign key ID columns to the various tables. This is not always the "many" side of the relationship. Only there was I able to map the related entity property to the appropriate property in the original entity. Selecting the "destination" entity would not allow me to select the properties that I needed to, and the error would still exist.
So in short, I had to map using the table related to the entity that had the "non-foreign key" ID fields corresponding to the various entities' (and their tables') primary keys that I needed to associate.
Entity A
various other properties...
Id
ContactId
OrderId
etc.
Contact entity
Id
FirstName
LastName
etc.
In the mapping details, I selected Entity A's table. It then showed both ends of the association. I mapped its Entity A's Id property to its table's actual ID column (they had different names). I then mapped the Contact entity's Id field to the ContactId field on the A entity.
Simply select the many relationship table (*) from the Association>Edit Mapping & select the appropriate relationship