Readonly List and Delete

Readonly List and Delete

Old forum URL: forums.lhotka.net/forums/t/10083.aspx


Kirby posted on Wednesday, February 16, 2011

Hi,

I'm quite new to CSLA and at my first steps I stumbled over some basic concepts. Lets explain that in a little example:

Let's assume I have a simple list of customers (a large list) diplayed in a kind of search form. And lets imagine further I do not want to edit those customers, I only want to list them. So the BusinessListBase<CustomerList,CustomerInfo> where CustomerInfo is a ReadOnlyBase<CustomerInfo> would certainly the way to go. With this concept the user could view the customers in the list and double click to view a read only form with more customer data. So far so good....

Now I want to add a feature "DeleteCustomer". The user should be able to delete the customers either from the form or directly in the list. I assume I would call customerInfo.Delete() somewhere in the code. But i have a readonly list and a readonly BO! Do I really have to switch to a BusinessList instead of ROL? That seems odd... Even if I would decide to switch to a BusinessList then I had to call customerList.Remove(currentCustomer). Remember the customer list is huge. Should I then iterate thru all customers in order to check which one is deleted? I would prefer to call customer.Delete() and have the (readonly list) notified about the change (I do not want to reload the huge list). I have read the article http://www.lhotka.net/weblog/IAmWorkingOnMyUsingCSLANET30EbookAndWroteSomeContentThatIDontThinkImGoingToUseInTheBook.aspx and that seems a good solution (for updating). But does it work for delete as well?

I mean, in my list of customers I do not need undo or tracking nor business rules. Its simple a result list but it should have delete capabilities...

Any hints?

Regards

Kirby

JonnyBee replied on Wednesday, February 16, 2011

Hi,

With ReadOnly objects you should also use ReadOnlyListBase (and not BusinessListBase which is for Editable objects).

As the name indicates - a ReadOnly object is just that - ReadOnly. So to add a "delete" method i would implement as:

* a CommandObject that does the Delete on a given "customerId".
* a method in the ReadOnlyList that will first call the CommandObject for delete and the remove the Item from the list.

 

Kirby replied on Thursday, February 17, 2011

Hi JonnyBee,

thank you for your answer, but I'm still confused. From the documentation:

"A command object represents some server-side command or action, and it is used to encapsulate processing other than simple create, read, update, and delete operations."

For sure I want to delete but I want to do this on a ReadOnlyList. I think, what I need is something like a "ImmutableObjectsList". I do not want to change the objects itself but I want to delete them (if nessecary). I trust you that your suggestion will work out (I have not tried it so far) but it seems still odd that I have (for such a basic operation like delete) to code something "special". I want to stick with the CSLA concept, that's why I want to know how to solve this very common scenario with CSLA (the CSLA way and not something special).

With best regards

Dirk

 

 

JonnyBee replied on Thursday, February 17, 2011

First - a ReadOnly object should be readonly. This means: NO Delete, NO Edit, NO Save.

CommandObject is typically used in EditableObjects for data access that is not a typical CRUD operation. A ReadOnly object should only have Create/Read abd Update/Delete so if you wish to have a Delete method AND use the DataPortal on a readonly list you cannot do this a part of a normal DataAccess and should then use the CommandObject.

A ReadOnly list has no means for marking one or more objects for Delete and than perform the delete as part of a Save operation on the entire list. 

IMO: It is NOT a common scenario to load ReadOnly objects into a list and then delete objects.

Remember: If you were to load a readonly list as a child of BO object - how should you hande N-Level Undo and Deletes in the readOnly list. There's no intention to a Delete mechanism on ReadOnly objects in Csla.

Kirby replied on Thursday, February 17, 2011

Thank you for your explanation. I would accept the solution with the CommandObject but (please forgive me) it just feels wrong.

Maybe I'm completely on the wrong way. I don't have to use the ReadOnlyList - I just thought it would be the right way to do so.

May I come back to the sample scenario? When I want to display a (huge) list of customers and when I want to be able to delete customers, is then the ReadOnlyList together with the CommandObject you described the right way? Or would it be better to implement an editable list (e.g. BusinessList)? I mean there is no need for editing the customers but maybe this is a "cleaner" or simple better way to do this?

Just loading a big list of "objects" (e.g. customers) and be able to delete those objects must be a common scenario in a lot of business applications. Outlook has a list of emails, a CD-Collection management application has a list of CDs, a CRM application has a list of customers... That's why I think it should be supported "out of the box". Please correct me if I'm wrong.

Sorry for the questions but I just try to understand what is best way to go according to CSLA.

Thank you so much for your patient!

Regards

Dirk

 

JonnyBee replied on Thursday, February 17, 2011

Csla implements the "mobile object" pattern by using the DataPortal and a number of restrictions in terms of Data Access.

This can be a great challenge for large lists and hence the DiffGram sample to only send modified rows back to the server. By default, the entire object graph is sent back to the server, including unchanged and modified rows and deleted rows.

The advantage of using the command object is that only the necessary data is sent back to the server - not the entire list. But you must encapsulate the code in the ReadOnly list to be able to turn off IsReadOnly and remove the item if delete is successful.

Comparably - If you loaded a large list of EditableObjects and wanted to delete an item you would typicalle us "deferred deletion", ie mark the item for deletion (moved to DeletedList) and send the entire list (ALL items) to the server for update/delete.

Rethinking  - you should create an editable object (CustomerEdit) with a static Delete method for Immediate deletion. The CustomerEdit object would  be used similar to a command object for immediate deletion of the Customer. The same object may also be used for loading customer data and edit the selected customer from the readonly list.

Wrap the Delete code in the ReadOnly list so you can turn off IsReadOnly, remove item from readonly list and reset IsReadOnly.

ajj3085 replied on Thursday, February 17, 2011

Hi Dirk,

So you have a search, of which you get back a list of customers.  This is standard readonly / readonlylist behavior.

If you wish to enable deleting from the search results, a command object to do the delete is totally an appropriate way to go.  You already have everything you need to know to enable a delete, so why not?

Where you'd want Delete on a BusinessBase subclass would be more appropriate to enable delete while the user is already editing the customer object. 

Note that you have a lot of options here; you can do the command and have it do the delete, you can have an editable object on which you can call delete, or you can do both. 

It all boils down to your use case. 

So think of your various use cases; typically the search result object (CustomerInfo, a ReadOnlyBase subclass) will have a subset of the data you could find in the full customer edit screen.  Sometimes that will be enough information for the user to make a decision to delete the customer.  Sometimes not, and so the user will double click at which point you'd go through the expense of loading up the editable object (Customer, as BusinessBase root subclass).  The user checks out some stuff, then decides on the full information that they want to delete (and I assume you alway have a way to undo the delete as well, the defered delete).

Now, if you need to enable both use cases, behind the scenes you'd want to have a way to reuse logic, if there are some conditions which will prevent a user from actually deleting, then you'd encapulate that logic into another class which both methods can use to actually do the delete.

Hopefully this post gives you some ideas about where to go from here.  As I said, you have a lot of options, and which ones you chose depend on what you need to do.

Kirby replied on Friday, February 18, 2011

Thank You all for your contribution.

I thjink I have a solution. It was so easy but for me as a newbie not so obvious... The concept of making a ReadOnlyList not ReadOnly (for a while) and then turn back to ReadOnly that was the missing link.

I implemented on the CustomerList Business object:

 

 

 

 

 

 

 

 

 

 

public void CustomerDelete(int id)
{
   //Delete the customer
   
Customer customer = Customer.GetCustomer(id);
   customer.Delete();
   customer.Save();

 

 

 

   //remove customer from list
  
CustomerInfo customerInfo = CustomerInfo.GetCustomerInfo(id);
  
this.IsReadOnly = false;
   this.Remove(customerInfo);
  
this.IsReadOnly = true;
}

So I end up with having a ReadOnly list having ReadOnly customers. I can on request load an editable customer object (where I also implemented a Delete). The ReadOnlyList itself implements a Delete (see above), so now I can delete objects from a ReadOnly list - perfect!

Together with the link above I will be able to synchronize a ReadOnly list with information coming from editable objects and I will later implement the suggestion with the CommandObject (sounds like a perfect solution for large lists).

All of your information was very helpful!

Thank You so much!

Regards

Dirk

JonnyBee replied on Saturday, February 19, 2011

You could even create a static factory method on Customer for "immediate deletion" and avoid one round trip to the server:

        // this metohod will call DataPortal_Delete
        public static void DeleteCustomer(int id)
        {
            DataPortal.Delete<Customer>(id);
        }

// and on your readonly list

public void CustomerDelete(int id)
{
   //Delete the customer
  
Customer.DeleteCustomer(id);

   //remove customer from list
   var
customerInfo = this.First(p => p.Id == id);
  
this.IsReadOnly = false;
   this.Remove(customerInfo);
  
this.IsReadOnly = true;
}

Copyright (c) Marimer LLC