It's been asked a million times, its like this.
Say Invoice is the base class and InvoiceHistory is the class that simply inherits from Invoice.
When I do something like
invoiceList = session.CreateCriteria(typeof(Invoice)).List();
I get everything from Invoice (that I want, plus everything from InvoiceHistory).
Do I need to have an InvoiceBase and create derived versions for Invoice and InvoiceHistory?
I think this has to do with polymorphism in NHibernate. Try specifying polymorphism="explicit" on the mapping for your base-class (Invoice).
If you don't want to retrieve the invoicehistory for an invoice inheritance wouldn't do the trick. Even creating an InvoiceBase would not help. If you are using inheritance nhibernate will always return the most complex object that exists in database. So if there is a foreign key in the invoicehistory pointing to an invoice you will alway get the invoicehistory object instead of a simple invoice. This is a fundamental feature of nhibernate.
You could excplicitly fetch only the properties of invoice and map them by hand using a ResultTransformer (see Reference for more infos) or create and map a SimpleInvoice object also referencing the invoice table, but with the latter you may face some stales-state issues is you mix Invoice and SimpleInvoice within the same session.
Hope this helps.
Related
I have more experience with SQL databases than I do with Symfony and am hoping someone can clarify the association mappings on how Doctrine connects the database to Symfony.
Taking a one-to-many mapping between Category and Product as an example:
I have very little need to record productIDs as a long string in each category record and I assume that having it is an unnecessary overhead. If I really needed to get a list of all products in a category record in the future though then I assume I could just manually query it still?
By extension, to get the above, I would need a unidirectional many-to-one association. If this is the case though, then would I still (and how would I?) be able to control such things as on delete cascade if required?
I think you are not totally understanding how this works in Doctrine. I hope this helps:
If you do a one-to-many between your Category and Product (one category has many products) with doctrine then it means that all you need is a category_id column in your product table (product is in this case the owning side of the relationship). You can make the relationship bi-directional without any consequences for the category table. Doctrine will allow you to get the products for a category easily by doing:
$category->getProducts();
In the background a query will be performed where all products with matching category_id column are resolved from your database and added to the products collection in the Category entity.
Check the example in the docs. It is exactly like yours, but then a one-to-many between product and features.
To prevent all products from loading when querying your category you can mark the inverse side as fetch="EXTRA_LAZY".
If you still have questions after this, just leave a comment.
Update:
So to make it very clear: doctrine does not add a column inside the category table. In your case the products property only exist in the object model not in the database model.
I have a mapping in FluentNHibernate for a HasMany relationship and I'd like to specify a Table on it to override the default Table that nHibernate will look in to find those objects that I have many of. Does that make sense?
So lets say I have a table for Invoices and a table for InvoiceItems and lets say I have table called InvoiceItemsTwo.
I have a class for Invoice and a Class for InvoiceItems as well, and their mappings are pretty straight forward. I'd like to specify in my mapping for Invoice, that it should look for it's items in InvoiceItemsTwo instead of the default InvoiceItems.
So my mapping of that relationship looks like this
HasMany(c => c.InvoiceItems).Cascade.SaveUpdate().Table("InvoiceItemsTwo");
But this doesn't work. I keep getting an error from my website at runtime that says Invalid object name 'InvoiceItems'.
Why is it ignoring the fact that I am explicitly specifying the Table in my mapping on the relationship?
I tried dumping the mapping at run time and it's being setup something like this
<bag cascade="save-update" table="InvoiceItemsTwo">
Any ideas?
The table attribute applies only to many-to-many relationships, not one-to-many.
you can't specify a different table in your mapping class. Fluent NHibernate uses the class mapped on the property list (InvoiceItems).
If yoy want to use another class to map your details table you must create a InvoceItemsTwo class and map it in your master table class.
You could map the list as composite-element instead of a one-to-many relation and then map it to another table. But it is not a good idea. Consider that NH needs to know where to store an object which is in memory. So it may happen that the object is stored in the wrong table.
Either store all the InvoiceItems in separate tables using composite-element instead of one-to-many and components instead of many-to-one (however this is called in Fluent).
Or store all the InvoiceItems in the same table and use regular references.
I have 2 domain classes with a many-to-many relationship in grails: decks and cards.
The setup looks like this:
class Deck {
static hasMany = [cards: Card]
}
class Card {
static hasMany = [decks: Deck]
static belongsTo = Deck
}
After I delete a deck, I want to also delete all cards which no longer belong to a deck. The easiest way to accomplish this is to write something like the following sql:
delete from card where card.id not in(select card_id from deck_cards);
However, I can't figure out how to write a HQL query which will resolve to this SQL because the join table, deck_cards, does not have a corresponding grails domain class. I can't write this statement using normal joins because HQL doesn't let you use joins in delete statements, and if I use a subquery to get around this restriction mySQL complains because you're not allowed to refer to the table you're deleting from in the "from" section of the subquery.
I also tried using the hibernate "delete-orphan" cascade option but that results in all cards being deleted when a deck is deleted even if those cards also belong to other decks. I'm going crazy - this seems like it should be a simple task.
edit
There seems to be some confusion about this specific use of "decks" and "cards". In this application, the "cards" are flashcards and there can be tens of thousands of them in a deck. Also, it is sometimes necessary to make a copy of a deck so that users can edit it as they see fit. In this scenario, rather than copying all the cards over, the new deck will just reference the same cards as the old deck, and if a card is changed only then will a new card be created. Also, while I can do this delete in a loop in groovy, it will be very slow and resource-intensive since it will generate tens of thousands of sql delete statements rather than just 1 (using the above sql). Is there no way to access a property of the join table in HQL?
First, I don't see the point in your entities.
It is illogical to make a card belong to more than one deck. And it is illogical to have both belongTo and hasMany.
Anyway, Don't use HQL for delete.
If you actually need a OneToMany, use session.remove(deck) and set the cascade of cards to REMOVE or ALL.
If you really want ManyToMany, do the checks manually on the entities. In pseudocode (since I don't know grails):
for (Card card : deck.cards} {
if (card.decks.size == 0) {
session.remove(card);
}
}
I won't be answering the technical side, but challenging the model. I hope this will also be valuable to you :-)
Functionally, it seems to me that your two objects don't have the same lifecycle:
Decks are changing : they are created, filled with Cards, modified, and deleted. They certainly need to be persisted to your database, because you wouldn't be able to recreate them using code otherwise.
Cards are constant : the set of all cards is known from the beginning, they keep existing. If you delete a Card once in the database, then you will need to recreate the same Card later when someone needs to put it in a Deck, so in all cases you will have a data structure that is responsible for providing the list of possible Cards. If they are not saved in your database, you could recreate them...
In the model you give, the cards have a set of Decks that hold them. But that information has the same lifecycle than the Decks' (changing), so I suggest to hold the association only on the Deck's side (uni-directional Many-To-Many relationship).
Now you've done that, your Cards are really constant information, so they don't even need to be persisted into the database. You would still have a second table (in addition to the Deck), but that Card table would only contain the identifying information for the Card (could be a simple integer 1 to 52, or two values, depending what you need to "select" in your queries), and not other fields (an image, the strength, some points etc...).
In Hibernate, these choices turns the Many-To-Many relationship to a Collection of values (see Hibernate reference).
With a Collection of Values, Card is not an Entity but a Component. And you don't have to delete them, everything is automatically taken care by Hibernate.
I've got a parent and child object. Depending on a value in the parent object changes the table for the child object. So for example if the parent object had a reference "01" then it will look in the following table "Child01" whereas if the reference was "02" then it would look in the table "Child02". All the child tables are the same as in number of columns/names/etc.
My question is that how can I tell Fluent Nhibernate or nhibernate which table to look at as each parent object is unique and can reference a number of different child tables?
I've looked at the IClassConvention in Fluent but this seems to only be called when the session is created rather than each time an object is created.
I found only two methods to do this.
Close and recreate the nhibernate session every time another dynamic table needs to be looked at. On creating the session use IClassConvention to dynamically calculate the name based on user data. I found this very intensive as its a large database and a costly operation to create the session every time.
Use POCO object for these tables with custom data access.
As statichippo stated I could use a basechild object and have multiple child object. Due to the database size and the number of dynamic table this wasn't really a valid option.
Neither of my two solutions I was particularly happy with but the POCO's seemed the best way for my problem.
NHibernate is intended to be an object relational mappers. It sounds like you're doing more of a scripting style and hoping to map your data instead of working in an OOP manner.
It sounds like you have the makings of an class hierarchy though. What it sounds like you're trying to create in your code (and then map accordingly) is a hierarchy of different kinds of children:
BaseChild
--> SmartChild
--> DumbChild
Each child is either smart or dumb, but since they all have a FirstName, LastName, Age, etc, they all are instances of the BaseChild class which defines these. The only differences might be that the SmartChild has an IQ and the DumbChild has a FavoriteFootballTeam (this is just an example, no offense to anyone of course ;).
NHibernate will let you map this sort of relationship in many ways. There could be 1 table that encompasses all classes or (what it sounds like you want in your case), one table per class.
Did I understand the issue/what you're looking for?
I've got a scenario something like this mock class heirachy
Order
OrderLine
Product
Customer
OrderNotes
which creates some tables like
Customer
Product
CustomerOrderNotes (CustomerId, OrderId)
Order (CustomerId)
OrderLines (OrderId, ProductId)
I've got this mapped to NHibernate and everything is working fine.
So now I want to create an in edit version of this object heirachy, and persist it to the database as well.
I'm using asp.net and want to save the in edit changes to separate rows, and then only when publish is pushed to commit the changes to the live row. (I'm planning on doing the copying from the edit data to the live data)
Using the same object model is it possible to store the in edit data in separate tables?
If not I could create an EditOrder class that derives from Order, but then EditOrder would still point to OrderLine, and Customer. So any changes from OrderLine and Customer would get saved to the live rows.
For NHibernate it appears I would need to create a separate heirachy
EditOrder
EditOrderLine
EditProduct
EditCustomer
EditCustomerNotes
without creating a generic behemoth that let you defined each class used in this heirachy I'm not sure which route to take.
I really want to use one class heirachy, rather than maintain two class heirachies.
The other option is to serialize the object heirachy for in edit onto the user class. But then if one of the class changes I'll have to wipe out the data, rather than run a database migration script.
Another solution is to use another database/session factory with different mapping files.
What is the recommended way of handling a scenario like this?
The two sets of tables are there to support two different states (published/awaiting approval (or the like)).
If possible, I recommend making this state explicit in your model, and save everything in the same table.
The client of the published objects will then somehow have to exclude the non-published objects.