This question relates to MongoDB with mongoid. My use case is as follows:
I have an Address entity that can be used in many different contexts, e.g. it could be the address of a customer, vendor, user, etc. In addition to that, a customer, for example, can have multiple addresses, such as an office address, a delivery address, and more.
Here is the Address entity, for example:
class Address
include Mongoid::Document
field :suburb, type: String
field :city, type: String
field :postcode, type: String
field :country, type: String
end
From the customer side, my thinking is that I would have the following:
class Customer
include Mongoid::Document
has_many :customer_addresses
end
class CustomerAddress
include Mongoid::Document
field :address_type, type: String
has_one :address
belongs_to :customer
end
According to the mongoid documentation, I need to put a belongs_to macro into Address to point back to the CustomerAddress entity for it to work properly.
However, Address, in this case, is multi-purpose. It could also be a vendor address, user address, or belong to any other entity that needs an address.
Perhaps I am thinking too much in terms of relational databases? What is the MongoDB approach for solving this problem?
Secondly, if I didn't want a CustomerAddress entity, but wanted different fields on Customer, such as :office_address and :delivery_address, each resolving to an Address, how would I do that?
See https://docs.mongodb.com/mongoid/master/tutorials/mongoid-relations/#polymorphism for handling multiple classes using an address.
CustomerAddress as a separate collection is likely not the best choice for MongoDB, look into embedding.
Use class_name option when the name of the association differs from the name of the class implementing it, which you'd need to have multiple associations of the same class.
Related
Is it possible to reference additional columns apart from the 'Code' and 'Name' columns when using a domain attribute in an entity?
E.g. A person entity has a code of '1' and a name of 'Smith' and a Gender of 'Male'
In a customer entity there is a domain value referencing the person entity which displays the following 1 {Smith}. The users would like an additional read only attribute which would copy the Gender value of 'Male' into the customer entity based on the domain value. Can this be done using out of the box MDS UI?
I know this is duplicate data and breaks normal form but for usability this would be useful. It would be the equivalent of referencing additional columns in an MS Access drop down list.
Many thanks in advance for any help
This is not possible with the standard UI. One option would be to develop a custom UI where you can handle these kind of requests.
If you want to stick with the standard product I can see a workaround but this is a bit of a "dirty" one.
You can misuse (abuse) the Name attribute of the Person entity by adding a business rule to the Person entity that generates the content of the Name attribute as a concatenation of multiple attributes. You of course need an additional attribute that serves as a place holder for the original Name. The concatenated field will then show in your customer entity.
One question that does come to mind is why a user would like/need to see the gender of a person in a customer list? As you have a separate Person entity I expect you to have multiple persons per customers. What would the gender of one person - even if it is the main contact - matter?
I'm wondering on how to do a many to many relationship with mongoid. Here is a visual representation of the models, with the small ones being join tables:
!http://i.imgur.com/lJxoRSb.jpg
I have set up my model like this (as an example) using RoR:
class Event
include Mongoid::Document
field :name, type: String
field :place, type: String
field :when, type: String
field :price, type: Integer
field :participants, type: Integer
field :short_description, type: String
has_many :users
#has_many :users, :through => :user_events
end
what would i need to join the event model with user model with interest model (if this is even possible)? I know mongoid isn't the best option for this but i'm stuck with using it.
Thanks in advance!
Try the following:
embeds_many :user_events
See also http://mongoid.org/en/mongoid/v3/relations.html#embeds_many
Do not use join tables in MongoDB, use arrays of embedded objects/references instead. MongoDB has array values, take advantage of them!
With a many-to-many relationship, you have a choice on placing the references on the first collection, or the second collection, or on both. If you put references in both collections, you have to do your own updates for consistency as needed by your application.
I am building a project that involved car servicing. I have an admin panel which allows the creation of services, and each service has a number of checks to perform (The checks themselves and belong to multiple services). The solution looks like this:
class Service
include Mongoid::Document
field :name, type: String
field :price, type: Integer
has_and_belongs_to_many :checks
end
class Check
include Mongoid::Document
field :name, type: String
has_and_belongs_to_many :services
end
These checks are performed on an instance 'Appointment'. So when an appointment is carried out, all the necessary checks are displayed (depending on the type of service).
What is the best way to create and store an instance of these checks?
In mySQL, I would create an appointment_check table with appointment_id and check_id as a compound key, and have the details of the check in there.
Is this the best way to resolve this in MongoDB? But surely this involves a join..
Is there a solution I'm missing?
Thanks
MongoDB does not know the concept of joins. So in your case you would not have a appointment_check table, as the has_and_belongs_to_many are just arrays of ids, in both sides.
What I would do in your case, is to have a belongs_to :appointment in the Check model, so you can have a appointment_id and the check_id within the same document.
I have User and Address classes as follows:
class User
{
...
...
#OneToOne( cascade=CascadeType.ALL)
#JoinColumn(name="addr_id")
private Address address;
}
class Address
{
...
...
#OneToOne(mappedBy="address")
private User user;
}
Here my assumption is with this domain model I can associate one address to only one user(user.addr_id should be unique).
But with this domain model, I am able to create multiple users and associate them to the same address.
User u1 = new User();
//set data
Address addr1 = new Address();
//set data
u1.setAddress(addr1);
...
session.save(u1);
--> this is creating one address record with addr_id=1 and inserting one user record in user table with addr_id=1. Fine.
Again,
User u2 = new User();
//set data
Address addr1 = (Address) session.load(Address.class, 1);
//set data
u2.setAddress(addr1);
...
session.save(u2);
--> This is creating second user record and associating to existing address with addr_id=1, which is not desired.
I can use #OneToOne(..)#JoinColumn(name="addr_id", unique=true) to prevent this.
But what will be the difference of using #OneToOne rather than #ManyToOne(.., unique=true).
#OneToOne itself should impose "unique=true" condition..right?
-Siva
#OneToOne is annotating the Java to express the idea of the relationship between the two classes. If this was a #OneToMany then we'd have a collection instead. So reading the annotations we understand the realtionships, and the JPA runtime also understands those.
The actual policing of the one-to-one is performed in the database - we need the schema to have the uniqueness constraints. The #JoinColumn expresses how that relationship is manifest in the DatabaseSchema.This can be useful if we are generating the schema.
However in many cases we use bottom-up tools to generate the Java from the schema. In this case there's no actual need for the Java annotations to reflect the database constraints, from a Java perspective we just see the relationship.
An intelligent compiler might warn us if the semantics of our #JoinColumn doesn't match the #oneToOne, but I'm not sure whether current implementations do that.
OneToOne is an annotation describing the object model. It says what the cardinality of the association is. unique="true" is an indication to the "model-to-ddl" tool that there should be a unique cosntraint on this column. You can use such a tool, but you're also free to create and maintain the database schema yourself.
Whatever you choose to do, the JPA engine doesn't make a query each time the OneToOne association is modified to check that the cardinality is respected. All it does is assuming that the code is correct, and the unique constraint in the database will make sure that the cardinality is respected.
I have a table structure like the following:
Companies Addresses
********* *********
ID ID
AddressID ...
BillingAddressID ...
AddressID and BillingAddressID are foreign keys which are present in the Addresses table. When I generate my model based on this table instead of getting what I would expect to get (the AddressID, BillingAddressID) in the company class. I get the following:
public Addresses Addresses { .. }
public global::System.Data.Objects.DataClasses.EntityReference<Addresses> AddressesReference { .. }
public Addresses Addresses1 { .. }
public global::System.Data.Objects.DataClasses.EntityReference<Addresses> Addresses1Reference { .. }
It seems to be replacing BillingAddress with Addresses1 (not quite sure why that's happening). Also this seems to be common wherever I have a foreign key i.e. instead of the ID I get Table then the TableReference.
I think I can see whats happening i.e. instead of giving me the ID alone, it will be doing a lookup and finding the actual record the ID refers to. However, I am not quite sure what the TableReference field is for....
Can explain this a little better for me?
Thanks in advance.
Relationships are represented as objects in Entity Framework, in the same manner as entities. Even if you are not going to work a lot directly on them, relationship object are first class citizens in EF. EF kreates ObjectStateEntry objects for tracking changes on relationships, just like it does it for entities.
That is why there are two references. First one, AddressesReference is a reference to the relationship object, not the exact entity, and second one Addresses is actual entity.
Peter Chan (link), and Julia Lerman in her book Programming Entity Framework, 1st Edition, say that understanding how relationship works in EF is very important. Also they mention that this is first thing that is confusing developer when they start using EF.
The foreign keys are replaced by a reference to the entity (collection) the foreign key points to.
So to add an address to a company you would do something like:
Address a = new Address();
// ... set variables for address here
currentCompany.Addresses = a;
// or, the other way round (for collections)
a.Companies.Add(currentCompany);
EF uses the table names as the reference point when it builds the model and this is why you see "Addresses" and Addresses1". You can open up the entity model in the GUI format and click on each of the associations. These can be renamed to whatever you like, just click on the reference, view the mapping, ensure it is the one that maps "BillingAddressID" to "BillingAddressID" and rename that reference to "BillingAddress".
Note the current "Addresses" reference may be the one mapping the "BillingAddressID" so you have to check both references.
It would probably be best to change the mapping for "AddressID" to be "Address" instead of "Addresses" if it is a one to one mapping as well.