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)

Jun
22
2009

Grand Opening

Welcome to RIAServicesBlog.NET*

I am finally getting this blog up and running. Over the next month or so this blog will be primarily concentrated on three categories:

  1. RIA Services FAQ
  2. What is RIA Services?
  3. What isn't RIA Services?

The first category will include answers to the most asked questions on the RIA Services forum. To save time for everyone, the answers to FAQs will be linked to the blog from the forum.

The second and third categories are what I call The Elephant Guide to RIA Services.

The Blind Men and the Elephant

by John Godfrey Saxe

It was six men of Indostan, to learning much inclined,
who went to see the elephant (Though all of them were blind),
that each by observation, might satisfy his mind.

The first approached the elephant, and, happening to fall,
against his broad and sturdy side, at once began to bawl:
"God bless me! but the elephant, is nothing but a wall!"

The second feeling of the tusk, cried: "Ho! what have we here,
so very round and smooth and sharp? To me tis mighty clear,
this wonder of an elephant, is very like a spear!"

The third approached the animal, and, happening to take,
the squirming trunk within his hands, "I see," quoth he,
the elephant is very like a snake!"

The fourth reached out his eager hand, and felt about the knee:
"What most this wondrous beast is like, is mighty plain," quoth he;
"Tis clear enough the elephant is very like a tree."

The fifth, who chanced to touch the ear, Said; "E'en the blindest man
can tell what this resembles most; Deny the fact who can,
This marvel of an elephant, is very like a fan!"

The sixth no sooner had begun, about the beast to grope,
than, seizing on the swinging tail, that fell within his scope,
"I see," quothe he, "the elephant is very like a rope!"

And so these men of Indostan, disputed loud and long,
each in his own opinion, exceeding stiff and strong,
Though each was partly in the right, and all were in the wrong!

So, oft in theologic wars, the disputants, I ween,
tread on in utter ignorance, of what each other mean,
and prate about the elephant, not one of them has seen!

John Godfrey Saxe (1816 - 1887)


* Or RIAServices.Blog.com for those who like to Ctrl+Enter into web pages)

Month List