The Elephant and the Silverlight

Thoughts and analysis of Silverlight for business applications

Page List

    Interlude 2 - Diagram of MVVM and RIA Services

    I promise that the rest of DomainClient will be posted tonight, but John Papa just posted up a very easy to read overview of MVVM. I couldn’t help doodling on his graphic to indicate one way you can map RIA Services to MVVM. As always, I will be hitting these concepts in more detail later.

    RIAInMVVM

    Note: My crudely drawn lines are trying to show that the DomainContext is taking the place of the two original links.


    Permalink | Comments (1) | Post RSSRSS comment feed

    Interlude – Entities do not have children

    Since this is the first interlude, let me explain what an interlude is. I have the main series of articles for this blog planned out, but every so often I will feel the need to jump ahead and give a small sample of what I will be posting about in the future. This can be triggered by a tweet, a post in the message boards, or a passing thoughts catches my fancy.

    This particular interlude is about terminology. In RIA Services, every entity should be considered a top level entity. There is no such thing as a parent child relationship in RIA Services; all entities are equal to each other. The hows and whys of this I will cover in the EntityContainer/EntityList series. The point is, the correct terminology should be Entity and Associated Entities, not Parent and Children.

    Why is this important?

    When we talk about a parent/child releationship there are certain preconceptions we bring to the table. For example, we would expect that the child cannot exist without the parent. We would call such an object an “orphan”. In RIA Services, as there are no children, there are no orphans. If you delete the “parent” the “children” are still tracked in their respective EntityList, all that happened is that the key value that uses to be shared with the deleted entity was cleared severing the association. Granted, you may or may not fail a foreign key check when you get back to the database but that is a matter of correct programming.

    This goes back to swo’s question back on the EntityCollection where he asked why the Add and Remove methods were designed in the way that they were. The answer is here in the question of naming. If you use the words parent and child then removing the child from the parent would seem to imply that the child should be deleted. However, if you use the words Entity and Associated Entity that removing the Associated Entity from the Entity would indicate that you are simply severing the association. As are most things are in programming, it is all about finding the proper names for things so that we can correctly understand concepts.

    Ok, one thing on why RIA Services is designed this way

    RIA Services is actually designed to work a lot like a database does. If you created a SQL Database where all of the foreign keys were nullable and you had cascading turned on you would have something that would act a lot like RIA Services does. That database design would have the virtue of being able to model and other database design that you can come up with in SQL Server. Just something to think about.

    (Do not actually go and design a database that way, what works really well for a data model works horribly for an actual database.)


    Permalink | Comments (6) | Post RSSRSS comment feed

    Meet the DomainClient

    For those following along, I will be covering the Entity, EntityList, EntityContainer, DomainContext, and DomainService in the future and in that order, but for today I am jumping to the DomainClient. Roughly speaking, I am introducing each object in the reverse order of what you may expect. The point I am trying to make here is that RIA Services is more than just a bunch of meaningless plumbing designed to pump data from between the DomainService and the DomainDataSource. There is great power, great flexibility, and quite a bit of elegance to be found within RIA Services. Nowhere is this more apparent than with the DomainClient.

    Everything you thought you knew was wrong

    One of the early lessons that newcomers to RIA Services learns is that the DomainDataSource doesn’t actually do all the things that they think it does. The DomainDataSource doesn’t actually load data, the DomainDataSource doesn’t actually submit changes, and the DomainDataSource doesn’t actually store the entities. The DomainDataSource is a proxy that passes all of those commands to the DomainContext. Well, if you are reading this blog you are now a more advanced student of RIA Services so here is your next lesson: The DomainContext doesn’t do all the things you think it does. It doesn’t actually load data from the server and it doesn’t actually submit changes to the server; those jobs are actually done by the DomainClient. (It also isn’t really where the entities are stored, come back for the EntityContainer post for more info.)

    Power of Simplicity, Flexibility of Abstraction

    The DomainClient does three things: Query, Submit, and Invoke. Each of the three has a public Begin, Cancel,  and End function and each of those has a protected abstract version that has a name ending with Core. For example, there is both a public BeginQuery and a protected abstract BeginQueryCore. The DomainClient class itself is abstract and cannot be used directly; you must use one of the two provided implementations or create your own implementation

    Each public method of the DomainClient does an argument validity check, wraps the callback inside its own callback, in the case of a BeginSubmit converts the ChangeSet into a list of EntityOperation objects, and finally passes it all to the protected Core method. That is it, that is all that the DomainClient does. Everything else is up to the particular implementation of DomainClient.

    Notice I haven’t said anything about the DomainService; that is because the DomainClient and DomainContext are actually completely abstracted from the DomainService and whatever type of communication is going to be used to talk to that DomainService. In fact, your specific implementation of DomainClient may not even be talking to a DomainService at all. This is quite ironic considering that the DomainContext is usually generated by analyzing a compiled DomainService. Currently, the generated DomainContext that must of us deal with is hard coded to use the HttpDomainClient. The HttpDomainClient is a a one trick pony that only knows how to communicate with the DataServiceFactory (aka DataService.axd) but that will change when what is currently named the AtomDomainClient becomes the default implementation in the PDC release of RIA Services.

    Wilco Bauwer has a very cool demo showing how the AtomDomainClient can connect directly to an Azure service.  Without a DomainService the code generator doesn’t work so Wilco uses a few T4 templates to generate the Entities and DomainContext. Future versions of RIA Services, meaning after the initial release next year, are going to use T4 templates for all code generation. This will make it even easier going forward to use the RIA Services client with back ends other than the DomainService.

    Wrap-Up

    There are going to be several more posts (more code, less text) on the DomainClient before I move on in in the future, but I want to wrap up this post before all this text puts everyone to sleep. Some important thoughts I would like you to take from this article are:

    • The DomainClient is the client side object in RIA Services that actually performs does the Load, Submit, and Invoke actions that we ask the DomainContext to do.
    • The DomainClient is an abstract class that has no dependencies on how communications will be performed or what is being communicated with.
    • The DomainClient has no methods marked internal, this makes it really easy for us to implement.
    • The DomainClient is so simple that creating your own implementation is not difficult. It would be really easy to mock the DomainClient for unit tests.
    Detour

    I have come to the realization that I need to move on to the Entity and other, more interesting objects. The main problem is that I don’t want to cover the HttpDomainClient and the AtomDomainClient since both of them are temporary code but talking about the code in abstract is just…boring to write about. So, I am moving on. If anyone has any specific questions about the DomainClient and how it works let me know and I will get them answered.


    Permalink | Comments (9) | Post RSSRSS comment feed

    The Problem with the DomainDataSource

    WARNING: This post is not meant to be documentation on the DomainDataSource. Just a stream of consciousness mini-rant on DomainDataSource posted here because the 140 characters that Twitter limits me to was too few.

    Jeff Handley has a poll going on the DomainDataSource. Please check it out and give an answer.

    Since the question is on the table, I decided to put together my own thoughts on the subject. I have not been shy to state that I simply do not use the DomainDataSource. Personally, I find it clunky and not nearly as refined as the rest of RIA Services. It also does not work well with my ViewModel. I think what Jeff is trying to figure out though is why that is. I can say it is clunky, we can all say it doesn’t feel right, but can we put our finger on what the problem is?

    I think the fundamental problem with the DomainDataSource is that it is not extensible at all. It is a completely sealed black box and there is very little way for us to extend it. This isn’t nearly as refined and elegant as the rest of RIA Services, such as the DomainContext which uses an EntityContainer to store all of the EntityLists and the DomainClient to talk to the server. If we want we want RIA Services to talk to the server using a port with everything under ROT13 encryption we can do that, we just have to create our own DomainClient that does that and tell the DomainContext to use it. We can’t do anything like that with the DomainDataSource. It just sits there in the XAML talking directly to our DomainContext and cutting our code completely out of the loop.

    What makes the DDS really annoying though is that the really useful paging code is locked inside it and its internal lackey the EntityCollectionView. I still live in hope that this will be fixed and that we will get a back end object that can generate the paging queries.

    So, what is the DomainDataSource doing exactly (this is not meant to be a full list)?

    1. Declarative access to DomainContext status (IsBusy, IsLoading, IsSubmittingChanges, etc.)
    2. Paging display attributes (PageSize)
    3. AutoLoad (which is data access logic)
    4. Paging load attributes (LoadSize) (data access logic)
    5. Setting the query name
    6. Setting the query attributes
    7. Submit changes

    I would have to say that from a MVVM perspective, 3, 4, 5, 6, and 7 are all problematic to me. The UI shouldn’t be worrying about the name of the query, how many records are being loaded outside of the PageSize, and I don’t think the UI should know what of its bound values are being used to filter queries. Letting the UI call directly to the DomainContext to SubmitChanges is also a big problem for me.  I do like the idea of a UI object that can allow binding of DomainContext statuses such as IsLoading and setting page size is a definite UI job.


    Permalink | Comments (14) | Post RSSRSS comment feed

    Meet the EntityRef and the AssociationAttribute

    Today I am going to cover the EntityRef and the AssociationAttribute, but first some cleanup on the EntityCollection. In the Advanced EntityCollection post I had part of the constructor explained incorrectly, it has been corrected as well as some cleanup on the code to make it more understandable.

    The EntityRef

    The EntityRef is the one-to-one relationship version of the EntityCollection, which means it is probably even less well known. Like the EntityCollection, the EntityRef has two different jobs depending on if the Entity is attached to an EntityList or not. However, the EntityRef is not directly exposed by the Entity, instead it is used to back a property with the type of the associated Entity. Here is the Book Entity’s Library property, the other side of the association covered in the EntityCollection posts.

    [Association("Library_Book", "LibraryId", "LibraryId", IsForeignKey=true)] 
    [XmlIgnore()] 
    public Library Library 
    { 
        get 
        { 
            if ((this._library == null)) 
            { 
                this._library = new EntityRef<Library>(this, "Library", this.FilterLibrary); 
            } 
            return this._library.Entity; 
        } 
        set 
        { 
            Library previous = this.Library; 
            if ((previous != value)) 
            { 
                this.ValidateProperty("Library", value); 
                if ((previous != null)) 
                { 
                    this._library.Entity = null; 
                    previous.Book.Remove(this); 
                } 
                this._library.Entity = value; 
                if ((value != null)) 
                { 
                    value.Book.Add(this); 
                    this.LibraryId = value.LibraryId; 
                } 
                else 
                { 
                    this.LibraryId = default(Nullable<Guid>); 
                } 
                this.RaisePropertyChanged("Library"); 
            } 
        } 
    }
    
    private bool FilterLibrary(Library entity) 
    { 
        return (entity.LibraryId == this.LibraryId); 
    }

    One important thing to note if you want to create your own properties backed by an EntityRef which are not read only, the this.ValidateProperty(“Library”, value) line is actually causing the getter to be called making sure that the _library field is getting populated. If you remove that line without replacing it you may get null reference exceptions.

     

    Meet the AssociationAttribute

    public AssociationAttribute( 
        string name, 
        string thisKey, 
        string otherKey 
    ) 

    Parameters
    name: Name of the association
    thisKey Comma separated list of the property names of the key values on this side of the association
    otherKey comma separated list of the property names of the key values on the other side of the association

    So, what does that pesky AssociationAttribute actually do? Both the EntityCollection and EntityRef require it but it is not obvious why that is. Also, what is the benefit of using EntityCollection and EntityRef over using a real CollectionView and a regular property?

    Both the EntityCollection and EntityRef monitor an EntityList for any changes to make sure that the associations are always kept up to date. However, if the various Filter method were called every time anything changed on the entities the performance issues would quickly get out of control. For example, lets say we have 10 libraries and we are entering 20 books with each book have 15 fields that we are changing. By the time we were done we would have called the FilterBook method 3,000 times (10 libraries * 20 books * 15 fields. This is not very efficient.

    To solve this problem, the EntityCollection and EntityRef only listen for changes made to those fields listed in the AssociationAttribute. This reduces us to 200 calls to FilterBook (10 libraries * 20 books * 1 field). By using the EntityRef and EntityCollection in our own code we are able to leverage this huge performance advantage ourselves. RIA Services probably has other uses for AssociationAttribute, but this is a really important one.


    Permalink | Comments (8) | Post RSSRSS comment feed