Sep
3
2009

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.

Sep
2
2009

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.

Sep
1
2009

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.

Aug
30
2009

Advanced EntityCollection

Previously,I gave an overview of the EntityCollection. In this post we are going to look at how the EntityCollection actually works and how we can add our own EntityCollections to extend our client side entities.

First, lets look at how RIA Services generates an EntityCollection during code generation

private EntityCollection<Book> _books; 

[Association("Library_Book", "LibraryId", "LibraryId")] 
[XmlIgnore()] 
public EntityCollection<Book> Books 
{ 
    get 
    { 
        if ((this._books == null)) 
        { 
            this._books = new EntityCollection<Book>(this, "Books", 
                          this.FilterBooks, this.AttachBooks, this.DetachBooks); 
        } 
        return this._books; 
    } 
} 

private void AttachBooks(Book entity) 
{ 
    entity.Library= this; 
} 

private void DetachBooks(Book entity) 
{ 
    entity.Library= null; 
} 

private bool FilterBooks(Book entity) 
{ 
    return (entity.LibraryId == this.LibraryId); 
} 

 

Lets look at that constructor, from the documentation the constructor is defined as

public EntityCollection(
    Entity parent,
    string memberName,
    Func<TEntity, bool> entityPredicate,
    Action<TEntity> attachAction,
    Action<TEntity> detachAction
)
 

So, the generated code is creating a new instance of EntityCollection passing in the current entity as the parent, “Books” as the name of the property, and FilterBooks as the EntityCollection’s filter.

The AttachAction and DetachAction  are the actual methods (beyond some internal plumbing) that you are calling when you call EntityCollection.Add and EntityCollection.Remove. Now that you see the actual code perhaps my earlier advice on not using Detach and Attach for attached entities makes more sense.

The Fun Part

Now, here is the fun part. We can actually create our own EntityCollections. In the above example we have an collection of books. What if I want multiple collections of books each filtered by the type of book? This can easily be done using custom EntityCollections.

public sealed partial class Library 
{
private EntityCollection<Book> _mysteryBooks;
[Association("Library_MysteryBook", "LibraryId", "LibraryId,Category")] [XmlIgnore()] public EntityCollection<Book> MysteryBooks { get { if ((this._mysteryBooks == null)) { this._mysteryBooks = new EntityCollection<Book>(this, "Books", this.FilterMysteryBooks); } return this._mysteryBooks; } } private bool FilterMysteryBooks(Book entity) { return (FilterBooks(entity) && entity.Category == "Mystery"); } }

Here I am using the alternate constructor which doesn’t have attach and detach. In this case, I wanted my EntityCollection to be read only. I also called the original FilterBooks function in hopes that this would make future maintenance easier.

Keep in mind that EntityCollection isn’t really a CollectionView. There is no external refresh method, the EntityCollection only refreshes based on the information in the attached AssociationAttribute. That means only new Books, deleted Books, or changes to LibraryFk or Category will cause the EntityCollection to refresh.

Aug
29
2009

Getting to know the EntityCollection

Meet the EntityCollection

Other than the DomainClient, the EntityCollection is probably the least known part of RIA Services. This is a problem as the EntityCollection is probably the most used class other than the Entity itself. The primary job of the EnityCollection is to represent one to many relationships between entities. It does this in two different ways.

The Detached EntityCollection

When your entity is detached, meaning it isn’t tracked by an EntityList, the EntityCollection acts as a container of related entities. You can create an entire hierarchy of objects and it will all be held together by the EntityCollections. When you finally add your entity to an EntityList all of the related entities from the EntityCollections are also added to their respective EntityLists. This begins the EntityCollection’s other mode.

The Attached EntityCollection

For entities tracked by EntityLists, the EntityCollection takes on some of the attributes of a CollectionView where the EntityList is now the underlying container of entities. The EntityCollection listens for changes in the EntityList and uses a filter to determine what entities should be viewed, much like a CollectionView. However, unlike a CollectionView the EntityCollection does not have a Refresh method. This means that the filter method has to be static, only changes to the EntityList will change the contents of the EntityCollection.

Adding and Removing objects through the EntityCollection

The EntityCollection has Add and Remove methods and while dealing with detached entities these methods work fine. However, using those methods with attached entities can be confusing. The EntityCollection’s add and remove do not actually delete the entity, it just clears the values defined in the AssociationAttribute. This means that you have set the ParentID in the child table to Null or 0. This is probably not what you meant to do. In general, I would suggest not using the Add and Remove method of the EntityCollection when dealing with attached entities. Instead, deal directly with the EntityLists instead.

Continue to Advanced EntityCollection

Aug
24
2009

How to setup your DomainService using partial classes for easy maintenance

One of the common questions that gets asked in the RIA Services Forum is how to add additional tables to a DomainService. One of the best practices that has been developed by the RIA Services community is using partial classes to spread a DomainService across multiple files with one Entity in each partial class file. Here are the steps on how to do this.

I am starting with Shawn Wildermuth’s MVVM project since he has multiple tables. Here is what the EDMX looks like:

Model

First you need to add a new DomainService

AddNewItemOne

I am using a naming standard here of EntityName.DomainServiceName

After adding the DomainService the wizard will appear

OriginalAddNew

One of the nice features of the wizard is that you can change the name of the DomainService. We are going to take advantage of that to remove the entity name. Here is what the wizard looks like once we have completely filled it in. i have outlines what changed in red.

UPDATE: The DomainService wizard no longer allows you to change the name of the DomainService from within the wizard. You will need to edit the file manually after the wizard completes instead

ChangedAddNew

After pushing OK this is what the project will look like

ProjectResult

Finally we need to modify the DomainService to add a partial to the class definition

CodeChangeOne

Repeat this process for any additional entities you want in your domain service. The only difference is that you will also need to remove the [EnableClientAccess()] attribute from all other partial class files

CodeChangeTwo

Setting up your project using partial class makes it easy to add additional tables. If you want to regenerate an entity due to database changes then you will need to comment out the existing code and recompile first. The wizard will not regenerate metadata that already exists in the project.

Aug
20
2009

ApplyState and ExtractState with RIA Services Contrib

UPDATE: There is a new version of the ApplyState and ExtractState at http://www.riaservicesblog.net/Blog/post/Updated-ApplyStateExtractState-Library.aspx

Tomorrow Soon  Some day I am going to updating RIA Services Contrib with some new features. The existing T4 templates, as fun as they are, are going to left alone for now. I am going to look at them again after the PDC version of RIA Services is released. In the meantime, I am going to release some new utility classes that I have been putting together. The release is attached to this blog post and Codeplex will be updated tomorrow. 

This new contrib release adds ApplyState and ExtractState methods to Enity objects, an Import method to EntityList<T>, and an Export method to all IEnumerable<T> where T : Entity collections. To use the new code simply reference the RIAServicesContrib.dll and import the RiaServicesContrib.Extensions namespace.

Here are some usage examples:

Entity cloning

Person newPerson = newPerson();
newPerson.ApplyState(Nothing, existingPerson.ExtractState(ExtractType.ModifiedState);
newPerson.PersonId = Guid.NewGuid();
context.Persons.Add(newPerson);

Partial Save (i.e. save only a single change instead of the whole DomainContext)

PersonDomainContext tempContext = new PersonDomainContext();
Person savePerson = newPerson();
tempContext.Persons.Add(savePerson);
savePerson.ApplyState(originalPerson.ExtractState(ExtractType.OriginalState, ExtractType.ModifiedState);
tempContext.SubmitChanges();

Export EntityList and save to Isolated Storage

using IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication()
{
    using IsolatedStorageFileStream isfs = new IsolatedStorageFileStream(fileName, FileMode.OpenOrCreate, isf)
    {
        DataContractSerializer serializer = new DataContractSerializer(typeof(List<EntityStateSet>));
        serializer.WriteObject(isfs, context.Persons.Export());
        isfs.Close();
    }
}

Import information from Isolated Storage into EntityList

using IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication()
{
    using IsolatedStorageFileStream isfs = new IsolatedStorageFileStream(fileName, FileMode.Open, isf)
    {
        DataContractSerializer serializer = new DataContractSerializer(typeof(List<EntityStateSet>));
        context.Persons.Import(serializer.ReadObject(isfs));
        isfs.Close();
    }
}

Some things which might not be obvious is that the Export functionality can also be done against a LINQ query, allowing partial exports of entities. When I update CodePlex I am going to include better documentation of the API.

RiaServicesContrib.zip (12.97 kb)

Month List