This thread looks to be a little on the old side and therefore may no longer be relevant. Please see if there is a newer thread on the subject and ensure you're using the most recent build of any software if your question regards a particular product.
This thread has been locked and is no longer accepting new posts, if you have a question regarding this topic please email us at support@mindscape.co.nz
|
Hi,
I have a table in my domain that have a reference on itself. I have a column in this table that have a relation on the same table. Ex: InvoiceTable ---------------------- Id InvoiceTableId - Nullable (This field is nullable because an invoice can be a parent invoice of a sub-invoice)
When I try to delete a sub-invoice from the parent invoice, LightSpeed don't delete the row and set the InvoiceTableId to Null. Ex: subInvoice = ParentInvoice.Invoices.First() ParentInvoice.Invoices.Remove(subInvoice)
What can I do to tells LightSpeed to delete my row instead of setting the InvoiceTableId to Null?
Thank you.
|
|
|
At the moment you are removing subinvoice from its parent's Invoices collection. You have not asked us to delete it, only to de-parent it. In a dependent association, de-parenting does mean deletion. But this association is nullable: the subinvoice is allowed to exist independently of the parent. So we are able to de-parent without deleting, and we do. You may also be able to force cascade deletes by setting Dependent = true on the association (in the designer; DependentAttribute in code). This tells LightSpeed that the association is dependent even though it is nullable, so it should delete entities that get de-parented instead of letting them float free. I haven't tried this with associations to self, though. Failing that, call IUnitOfWork.Remove: uow.Remove(ParentInvoice.Invoices.First()); |
|
|
Hi Ivan,
Thanks for the deep explanation. I tried to set Dependent = true on the association which is already set to nullable but when I try to use it, LightSpeed throw an error.
Here is the error:
Mindscape.LightSpeed.LightSpeedException: The field [InvoiceTableId] on type [InvoiceTable] must be nullable as it represents a hierachical relation at Mindscape.LightSpeed.LightSpeedException.(Exception , String , Object[] ) at Mindscape.LightSpeed.LightSpeedException.(String , Object[] ) at Mindscape.LightSpeed.Model.ToManyModel.() at Mindscape.LightSpeed.Model.AssociationModel.(TypeModel ) at Mindscape.LightSpeed.Model.TypeModel.(IEnumerable`1 ) at Mindscape.LightSpeed.Model.TypeModel.GetTypeModel(Type ) at ..(Query , IList ) at Mindscape.LightSpeed.UnitOfWork.Find(Query query, IList results) at Mindscape.LightSpeed.UnitOfWorkBase.Find(Query query) at Mindscape.LightSpeed.Linq.Plan.SingleQueryPlan.ExecuteImmediate(IUnitOfWork unitOfWork, Type returnType) at Mindscape.LightSpeed.Linq.LinqQueryProvider.Execute(Expression expression) at Mindscape.LightSpeed.Linq.LinqQueryProvider.System.Linq.IQueryProvider.Execute(Expression expression) at Mindscape.LightSpeed.Linq.LinqQuery`1.GetEnumerator()
Have you any idea?
Thank you. |
|
|
Hi Ivan,
Thanks for the deep explanation. I tried to set Dependent = true on the association which is already set to nullable but when I try to use it, LightSpeed throw an error.
Here is the error:
Mindscape.LightSpeed.LightSpeedException: The field [InvoiceTableId] on type [InvoiceTable] must be nullable as it represents a hierachical relation at Mindscape.LightSpeed.LightSpeedException.(Exception , String , Object[] ) at Mindscape.LightSpeed.LightSpeedException.(String , Object[] ) at Mindscape.LightSpeed.Model.ToManyModel.() at Mindscape.LightSpeed.Model.AssociationModel.(TypeModel ) at Mindscape.LightSpeed.Model.TypeModel.(IEnumerable`1 ) at Mindscape.LightSpeed.Model.TypeModel.GetTypeModel(Type ) at ..(Query , IList ) at Mindscape.LightSpeed.UnitOfWork.Find(Query query, IList results) at Mindscape.LightSpeed.UnitOfWorkBase.Find(Query query) at Mindscape.LightSpeed.Linq.Plan.SingleQueryPlan.ExecuteImmediate(IUnitOfWork unitOfWork, Type returnType) at Mindscape.LightSpeed.Linq.LinqQueryProvider.Execute(Expression expression) at Mindscape.LightSpeed.Linq.LinqQueryProvider.System.Linq.IQueryProvider.Execute(Expression expression) at Mindscape.LightSpeed.Linq.LinqQuery`1.GetEnumerator()
Have you any idea?
Thank you. |
|
|
Hi Ivan,
Thanks for the deep explanation. I tried to set Dependent = true on the association which is already set to nullable but when I try to use it, LightSpeed throw an error.
Here is the error:
Mindscape.LightSpeed.LightSpeedException: The field [InvoiceTableId] on type [InvoiceTable] must be nullable as it represents a hierachical relation
Have you any idea?
Thank you. |
|
|
Sorry for the duplicate posts. The first time I tried to sent post, an error has been thrown from your server. |
|
|
Hmm, I did say I wasn't sure if Dependent would work on a self-association. I will try to look into this but for now you will have to use IUnitOfWork.Remove as previously mentioned. |
|
|
Thank you very much. I will use another table to store subInvoice in this case because the place where I remove subInvoice don't know about the unitOfWork. I work in a windowsForm application and the save to the UnitOfWork is late in the process after removing subInvoices. When I try to remove a line of invoice, the count of the lines in the invoice is decrease of 1 each time. When I do the same operation with the subInvoice, the count is not decrease and this is hard for me to figure it out another workflow to handle a correct count of the subInvoice. Thank you again. |
|
|
Hi Ivan,
It works when I call uow.Remove(invoice.SubInvoices) but if I have SubInvoices of SubInvoices, it don't work. If I have a folder A that contain a folder B and that folder B contain a folder C, how can I delete the tree folders when I delete the folder A?
Thank you.
|
|
|
That is because you are back to the original situation of having a nullable foreign key. You'll need to recursively walk the Subinvoices hierarchy calling Remove for each item. Another possible approach is to just let the parent IDs go null, then run a cleanup on the database to delete any subinvoices which no longer have parents. However you will still run into the recursion issue if subinvoices can have sub-subinvoices (you need to de-parent items to an arbitrary depth, and there's no way to do that in SQL), unless your database supports foreign key cascade delete (e.g. I think Oracle does). |
|
|
Hi Ivan, First, sorry to reply again to this post but the solution you provides to me is a little bit cumbersome. I use SQLite. I defined a foreign key on the invoice to self with cascade delete and cascade update. I also set in my connection the command PRAGMA foreign_keys = true; to tells SQLite engine to process the cascade actions. I defined the "Removal Behavior" to "NoAction" in the model. When I try to delete the parent invoice, the behavior is same like if I set the "Removal Behavior" to "SetNull". If in both cases the delete of the parent invoice set the InvoiceId of the subinvoice to Null, what is the difference with "NoAction" and "SetNull". Must I should not simply call a query "DELETE FROM Invoice WHERE Invoice.Id = X" where the engine of SQLite will process the work for me? I think creating a function to recursively delete all subinvoices is like trying to move a cane of tuna with a big boat or am I wrong?
Thank you. |
|
|
Hi,
Is my post has offended anyone because I don't have received no reply since 5 days. I just want to know if my understanding of NoAction property in a relation is correct because I have as strategy to delete an entry and let the database proceed the cascade delete but the NoAction don't seem to is really without action because my subInvoice's parent link was set to null like with the property removal behavior set to "SetNull".
Thank you and sorry again for my many replies. |
|
|
Sorry, we have been a bit busy and I'm afraid your message fell between the cracks. Thank you for chasing us up! It looks like none of the existing RemovalBehavior options currently do what you want, so we are going to take a look at adding a new option, but there are a couple of subtle issues that we need to look into. Just to confirm, we understand the problem is that you have a cascade delete in the database, but it is not having an effect because we do an UPDATE that de-parents the children before we DELETE the parent (so there is nothing to cascade to!), right? So you need an option to skip the UPDATE and just do the DELETE, correct? |
|
|
A quick update on this: we have a fix for this under way, but it's not going to make it into tonight's nightly build as we need to do some more testing. We'll keep you informed. |
|
|
Okay, we have a candidate solution for this coming up in tonight's nightly build. Set the RemovalBehavior on the association to NoActionNoCheck: this will cause it to skip the UPDATE statement and allow the database to perform the cascade delete. IMPORTANT: Because NoActionNoCheck tells LightSpeed to bypass its normal cascade delete checking, this can result in the unit of work containing stale entity states. You should aim to call IUnitOfWork.SaveChanges(true) as soon as possible after performing a Remove of an entity with a NoActionNoCheck association. Because NoActionNoCheck is dangerous, we have currently confined it to self-references, which we expect to be the main use case anyway. Please let us know whether this works for you or if you run into any bugs. |
|
|
I tried the last build (1 mars 2011) and its works perfectly. My UnitOfWork for this type of action have a very short lives. Thus, I don't have problem with the cache in the UnitOfWork. Thank you very much Ivan. Great job and very fast. |
|