Thursday, March 31, 2011

DomainDataSource and Composites, problem with HasChanges

There is a subtle bug in current version of WCF RIA (v1 sp1) related to using composites client-side. Sometimes when you change not only you CompositionRoot object but also one of its children and then submit that changes, you may notice that change tracking started behave strangely i.e. any further modifications of any part of composite will change entity’s HasChanges and DomainContext’s HasChanges to true, but associated DomainDataSource will remain with “no changes” (HasChanges == false). To fix that you need to do two things

  1. Subscribe on SubmittedChanges of your DomainDataSource
  2. AcceptChanges for your entire EntityContainer inside event handler

or speaking C#

YourDomainDataSource.SubmittedChanges += SubmittedChanges;
// workaround to prevent stale HasChanges on DDS
private void SubmittedChanges(object sender, SubmittedChangesEventArgs e)
{
    if (!e.HasError)
    {
        ((IChangeTracking)Context.EntityContainer).AcceptChanges();
    }
}

Monday, March 28, 2011

Composites in WCF RIA (take 2)

Composites are great! Unfortunately this feature of WCF RIA Services is probably one of the most misused and feared by many developers. Let’s just recap WHY it is great.

(for complete description read http://msdn.microsoft.com/en-us/library/ee707346%28v=VS.91%29.aspx)

  1. It gives you composite change tracking and commit/rollback support client-side, i.e. when you change any part of composite you effectively change the whole composite (CompositeRoot.HasChanges == true and all children included in change set)
  2. It gives you single “point of persistence” server-side, i.e. you can persist whole composite inside CRUD methods of its root entity

Point one gives you ability to change/commit/rollback all changes made to composite entity plus you can easily indicate UI that your composite entity has changes (just bind to CompositeRoot.HasChanges)

Point two allows you to encapsulate all you composition CRUD inside 3 methods

  • InsertCompositeRoot
  • UpdateCompositeRoot
  • DeleteCompositeRoot

ok, enough theory, let’s consider some code now

Our domain model will be simple, we have a Spy entity Winking smile Each spy can have multiple names and weapons given

How would our SpyUpdate method look like? (we are using LinqToEntitiesDomainService service)

// composition root
public void UpdateSpy(Spy spy)
{
    spy.Names.Clear();
    spy.Weapons.Clear();

    var original = ChangeSet.GetOriginal(spy);
    if (spy.EntityState == EntityState.Detached)
    {
        if(original != null)
        {
            ObjectContext.Spy.AttachAsModified(spy, original);
        }
        else
        {
            ObjectContext.Spy.Attach(spy);
        }
    }

    ApplyCompositeListChanges(spy, c => c.Names, ObjectContext.SpyName);
    ApplyCompositeListChanges(spy, c => c.Weapons, ObjectContext.SpyWeapon);
}

You might be wondering now, why we need to clear Names and Weapons in first two lines and the reason is … EF will choke if you don’t. When you attach composite root to EF context it will try to attach all related elements as well (names and weapons). It’s ok, the problem is that if you added more that one name, for example, EF will throw an exception on you with something like “Submit operation failed. An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key” (yes, our two new names would have the same empty key)

Don’t worry, we don’t lose that changes by clearing out collection… it will be handled inside ApplyCompositeListChanges method

private void ApplyCompositeListChanges<TEntity, TListElement>(TEntity root, 
    Expression<Func<TEntity, EntityCollection<TListElement>>> selector, 
    ObjectSet<TListElement> objectSet)
    where TEntity : EntityObject
    where TListElement : EntityObject
{
    foreach (TListElement change in ChangeSet.GetAssociatedChanges(root, selector))
    {
        var op = ChangeSet.GetChangeOperation(change);
        
        switch (op)
        {
            case ChangeOperation.Insert:
                if (change.EntityState == EntityState.Added) break;
                
                if (change.EntityState != EntityState.Detached)
                {
                    ObjectContext.ObjectStateManager.ChangeObjectState(change, EntityState.Added);
                }
                else
                {
                    objectSet.AddObject(change);
                }
                break;
            
            case ChangeOperation.Update:
                objectSet.AttachAsModified(change, ChangeSet.GetOriginal(change));
                break;
            
            case ChangeOperation.Delete:
                if (change.EntityState == EntityState.Detached)
                {
                    // RIA bug: EntityKey is null for deleted items ;( 
                    ObjectContext.CreateKey(change);
                    ObjectContext.Attach(change);
                }
                ObjectContext.DeleteObject(change);
                break;
            
            default:
                break;
        }
    }
}

As you can see the logic here is quite simple, we get changes associated to RootEntity (Spy in our case) and apply those changes to EF context one by one. The tricky part here is delete – at the moment of writing (WCF RIA V1 SP1) RIA has this strange behaviour (bug?) - all deleted entities in changeset would have empty EntityKey, preventing you from ObjectContext.Attach. The workaround is simple – we create EntityKey if it’s empty

public static void CreateKey(this ObjectContext context, EntityObject entity)
{
    if (entity.EntityKey == null)
    {
        entity.EntityKey = context.CreateEntityKey(context.GetEntitySetName(entity.GetType()), entity);
    }
}
public static string GetEntitySetName(this ObjectContext context, Type entityType)
{
    var type = entityType;
    while (type != null)
    {
        foreach (EdmEntityTypeAttribute typeattr in 
            type.GetCustomAttributes(typeof (EdmEntityTypeAttribute), false))
        {
            var container = context.MetadataWorkspace
                .GetEntityContainer(context.DefaultContainerName, DataSpace.CSpace);
            var entitySetName = 
                (from meta in container.BaseEntitySets
                where meta.ElementType.FullName == typeattr.NamespaceName + "." + typeattr.Name
                select meta.Name).FirstOrDefault();
            if (entitySetName != null) return entitySetName;
        }
        type = type.BaseType;
    }
    throw new InvalidOperationException(
        string.Format("Unable to determine EntitySetName of type '{0}'.", entityType));
}


In one of my previous posts I described how you can implement complete generic solution to save composites, however this explicit method we have just looked at could help you understand the logic behind it and can be used in real applications as well.

Happy coding!

Friday, March 25, 2011

Long time no see…

I’ve been away from blogging for quite a while, lots of project have been done during that time, literally had no time to blog... obvious excuse for being silent, I know Winking smile… but not anymore… let’s continue our quest to perfect code! Resume mode is on!

Wednesday, April 14, 2010

WCF RIA, Repository pattern and testability (Part 2)

Ok, let’s continue…

The idea of testability based on the ability to substitute execution context. And we usually achieve that by using IoC containers. However, I am strong follower of concept “Simplest thing that works” that’s why I introduce you to DataContext

Code Snippet
/// <summary>
/// Keeps ObjectContext for current request
/// </summary>
public static class DataContext
{
    [ThreadStatic] private static IObjectContext _current;

    public static IObjectContext Current
    {
        get { return _current; }
        internal set { _current = value; } // must be set only from BaseDomainService or UnitTestBase
    }
}

as you can see it’s just simplest implementation of Abstract Singleton and it can be easily substituted for our testing purposes. For “real” environment we can assign it here

Code Snippet
/// <summary>
/// Provides base repository and transactional support + common entity processing before save
/// </summary>
/// <typeparam name="T">ObjectContext</typeparam>
public abstract class DomainServiceBase<T> : LinqToEntitiesDomainService<T>
    where T : ObjectContext, IObjectContext, new()
{
    public override void Initialize(DomainServiceContext context)
    {
        base.Initialize(context);
        DataContext.Current = ObjectContext;
    }

For “test” environment here

Code Snippet
[TestClass]
public abstract class UnitTestBase
{
    [TestInitialize]
    public void MyTestInitialize()
    {
        DataContext.Current = PrepareDataContext();
    }

    protected abstract IObjectContext PrepareDataContext();
}

the last thing we need to do is to implement “test” versions of our main EF related abstractions IObjectSet and IObjectContext

Code Snippet
public class FakeObjectSet<TEntity> : IObjectSet<TEntity> where TEntity : class
{
    private readonly HashSet<TEntity> _data;
    private readonly IQueryable _query;

    public FakeObjectSet() : this(new List<TEntity>())
    {
    }

    public FakeObjectSet(IEnumerable<TEntity> testData)
    {
        _data = new HashSet<TEntity>(testData);
        _query = _data.AsQueryable();
    }

    #region IObjectSet<TEntity> Members

    public void AddObject(TEntity item)
    {
        _data.Add(item);
    }

    public void DeleteObject(TEntity item)
    {
        _data.Remove(item);
    }

    public void Detach(TEntity item)
    {
        _data.Remove(item);
    }

    public void Attach(TEntity item)
    {
        _data.Add(item);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return _data.GetEnumerator();
    }

    IEnumerator<TEntity> IEnumerable<TEntity>.GetEnumerator()
    {
        return _data.GetEnumerator();
    }

    Type IQueryable.ElementType
    {
        get { return _query.ElementType; }
    }

    Expression IQueryable.Expression
    {
        get { return _query.Expression; }
    }

    IQueryProvider IQueryable.Provider
    {
        get { return _query.Provider; }
    }

    #endregion
}

the code speaks for itself – our FakeObjectSet is just banal wrapper around HashSet. Next comes the sweet FakeDb

Code Snippet
public class FakeDb : IObjectContext
{
    protected Dictionary<Type, object> Sets = new Dictionary<Type, object>();

    public void AddEntity<T>(T entity) where T : EntityObject
    {
        if (entity == null) return;

        CreateObjectSet<T>().Attach(entity);
    }

    public void AddEntities<T>(IEnumerable<T> entities) where T : EntityObject
    {
        if (entities == null) return;

        foreach (var entity in entities)
        {
            AddEntity(entity);
        }
    }

    public IObjectSet<T> CreateObjectSet<T>() where T : class
    {
        object set;
        if (!Sets.TryGetValue(typeof(T), out set))
        {
            set = new FakeObjectSet<T>();
            Sets.Add(typeof(T), set);
        }
        return (FakeObjectSet<T>)set;
    }

    // override to provide some real DB like behaviour (ex: IDs generation)
    public virtual int SaveChanges()
    {
        return 1; // what a surprise ;)
    }

    public void Clear()
    {
        Sets.Clear();
    }
}

again – simple, straightforward implementation – our FakeDB is just a set of FakeObjectSets or “in memory DB-like structure” for simplicity. Well, so far so good, let’s write our first Unit Test

Code Snippet
[TestClass]
public class UnitTestExample : UnitTestBase
{
    protected override IObjectContext PrepareDataContext()
    {
        // for integration-style UT with real DB
        // return new TestEntities();
        var db = new FakeDb();
        db.AddEntity(new Order { Name = "Test" });
        db.AddEntity(new Order { Name = "Test1" });
        return db;
    }

    [TestMethod]
    public void TestMethod1()
    {
        var ordersRepository = new RepositoryBase<Order>();
        Assert.AreEqual(2, ordersRepository.Query.Count());
        var order = ordersRepository.Query.Where(c => c.Name == "Test").SingleOrDefault();
        Assert.IsNotNull(order);
    }
}

Great result – with the minimum amount of plumbing we substituted our real DB with in-memory twin that we can fill with test data we need. And if you prefer integration-style unit test with real test DB, you can easily do that as well. And of course all standard CRUD will work ;)

Friday, April 9, 2010

WCF RIA, Repository pattern and testability

When you developing WCF RIA domain services you usually highly coupled with underlying data access layer (DAL) technology of your choice. It’s usually Entity Framework (EF), LinqToSQL, nHibernate, pure ADO.NET or other ORM/DAL frameworks. It’s great, however it brings following issues

  1. Learning curve for some ORM/DAL frameworks can be painful (it may include convoluted APIs with leaking abstractions)
  2. Due to coupling it’s hard/impossible to switch to new DAL framework if you bump into some major issues with you current one
  3. Lack of testability with some of ORM/DAL frameworks

That’s why it makes sense to introduce another level of abstraction/indirection between your domain logic and DAL. It must be simple, testable and well known concept. Well, and we have one – it’s famous Repository pattern.

There are many ways you can define/implement it, let’s consider my version. In this example we will implement generic repository for EF’s entities. First of all – let’s define abstraction

Code Snippet
public interface IRepository<T> where T : EntityObject
{
    // Query
    IQueryable<T> Query { get; }

    // CRUD
    void Insert(T entity);
    void Update(T entity);
    void Delete(T entity);
}

As you can see our repository is quite succinct. It can do two things – Query for data and CRUD. And it seems that learning curve for using this abstraction is minimal (read - developers will love it)

As long as we trying to adapt standard code generated by EF designer for our repository needs we need to introduce some more interfaces to abstract away our custom ObjectContext

Code Snippet
public interface IUnitOfWork
{
    int SaveChanges();
}

This is abstraction for EF’s ObjectContext which is essentially implementation of UnitOfWork (UoW) pattern. However it’s not only UoW, it’s also entity sets container, which can be abstracted away by

Code Snippet
public interface IObjectContext : IUnitOfWork
{
    IObjectSet<T> CreateObjectSet<T>() where T : class;
}

ok, so far so good, now we need to make our custom ObjectContext (generated by EF designer) to implement this abstraction. It can be easily done by partial class like this

Code Snippet
public partial class TestEntities : IObjectContext
{
    public new IObjectSet<T> CreateObjectSet<T>() where T : class
    {
        return base.CreateObjectSet<T>();
    }
}

great, now we can implement our generic repository

Code Snippet
/// <summary>
/// Base repository, provides basic CRUD, Query and IUnitOfWork
/// Be aware, that unit of work is shared across all repositories,
/// so first SaveChanges() will save all changes made by all repositories before
/// </summary>
/// <typeparam name="T">Type of entity you working with</typeparam>
public class RepositoryBase<T> : IRepository<T>, IUnitOfWork where T : EntityObject
{
    private readonly IObjectContext _context;
    private readonly IObjectSet<T> _objectSet;

    public RepositoryBase()
    {
        if (DataContext.Current == null) throw new Exception("DataContext is undefined");
        _context = DataContext.Current;
        _objectSet = _context.CreateObjectSet<T>();
    }

    #region IRepository<T> Members

    public IQueryable<T> Query
    {
        get { return _objectSet; }
    }

    public virtual void Insert(T entity)
    {
        if (entity.EntityState == EntityState.Added) return;
        if (entity.EntityState == EntityState.Unchanged)
        {
            var ctx = _context as ObjectContext;
            if (ctx == null) return;
            ctx.ObjectStateManager.ChangeObjectState(entity, EntityState.Added);
        }
        else
        {
            _objectSet.AddObject(entity);
        }
    }

    public virtual void Update(T entity)
    {
        var ctx = _context as ObjectContext;
        if (ctx == null) return;
        if (entity.EntityState == EntityState.Detached) ctx.Attach(entity);
        ctx.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
    }

    public virtual void Delete(T entity)
    {
        if (entity.EntityState == EntityState.Detached) _objectSet.Attach(entity);
        _objectSet.DeleteObject(entity);
    }

    #endregion

    #region IUnitOfWork Members

    public virtual int SaveChanges()
    {
        // Update common fields
        var ctx = _context as ObjectContext;
        if (ctx != null)
        {
            var changes = ctx.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified);
            foreach (var entity in changes.Select(objectStateEntry => objectStateEntry.Entity))
            {
                UpdateHelper.UpdateCommonFields(entity);
            }
        }
        return _context.SaveChanges();
    }

    #endregion
}

As you can see our generic repository mixes Repository and UnitOfWork patterns, which will allow us to do batch data modifications and save in one go.

The usage of this generic class is simple, elegant and straightforward

Code Snippet
var orderRepository = new RepositoryBase<Order>();
var order = orderRepository.Query.First(o => o.ID == id);
order.Name = "Modified on server!";
orderRepository.SaveChanges();

You may wonder what is that magical DataContext our Repository depends on? Well, wait for the next post ;)

to be continued…

Monday, April 5, 2010

RIA and DTO (Part 2)

Ok, let’s make our DTO a bit more complex (or more real life like I would say)

Code Snippet
public class MyCustomDTO
{
    [Key]
    public int ID { get; set; }

    public int MyPayload { get; set; }
    public string MyOtherPayload { get; set; }
    
    [Include]
    [Association("MyCustomDTO_MyItem", "ID", "ParentID")]
    public IEnumerable<MyItem> MyItems { get; set; }
}

public class MyItem
{
    [Key]
    public int ID { get; set; }
    public int ParentID { get; set; }

    public string Name { get; set; }
    public int Value { get; set; }
}

so we added list of MyItems to our DTO. We also marked this list with [Include] and [Association]. It’s very important part and soon you’ll see why. Let’s test our DTO, is it really able to transfer data to/from client? Server-side is

Code Snippet
[Invoke]
public MyCustomDTO MyOtherOperation(MyCustomDTO data)
{
    data.MyItems = new List<MyItem> { new MyItem { Name = "new", Value = 72 } };
    return data;
}

Note: for some strange reason RIA won’t allow you to use sets/enumerations of DTO as parameter, so the following will not compile. Be aware!

Code Snippet
[Invoke]
public void MyOtherOperation(IEnumerable<MyCustomDTO> data)

the workaround is simple – just encapsulate your list inside another DTO class ;)

ok, now client side

Code Snippet
var data = new MyCustomDTO
{
    MyPayload = 13,
    MyOtherPayload = "Test"
};
ctx.MyOtherOperation(data,
    op =>
    {
        var result = op.Value;
        Debug.Assert(result.MyItems.Count == 1);
    },
    null);

Let’s run it… boom! Assertion failed! We expected our list be non empty but it is ;( You might ask – why? We did all good server side. Well.. not really ;) Here comes very important part – how client client side code generated by RIA handle references. It does handle it via associations. The same way as relational databases handle foreign key associations. So to make it work you have to provide valid values of properties that make association. Here is the code it uses internally (generated client side)

Code Snippet
[Association("MyCustomDTO_MyItem", "ID", "ParentID")]
public EntityCollection<MyItem> MyItems
{
    get
    {
        if ((this._myItems == null))
        {
            this._myItems = new EntityCollection<MyItem>(this, "MyItems", this.FilterMyItems);
        }
        return this._myItems;
    }
}

and the magic happens here

Code Snippet
private bool FilterMyItems(MyItem entity)
{
    return (entity.ParentID == this.ID);
}

so, as you now see, to fix our problem we have to do this

Code Snippet
var data = new MyCustomDTO
{
    ID  = 1,
    MyPayload = 13,
    MyOtherPayload = "Test",
};
data.MyItems.Add(new MyItem { ID = 1, ParentID = 1, Name = "client", Value = 5 });

Well, let’s give it another go. F5… same result! The sad truth is that unfortunately at the moment [Invoke] operations don't support complex composite DTOs. The only place you can use it is either [Query] methods (as a result) or in Submit based operations. Which means that we can either wait till RIA team fixes this awkward functional gap or we could use normal WCF service or this simple but ugly workaround

Server side

Code Snippet
[Insert]
public void MyItemDummyInsert(MyItem data) { }

[Insert]
public void MyOperation(MyCustomDTO data)

Client side

Code Snippet
var ctx = (OrderContext)orderDomainDataSource.DomainContext;
var data = new MyCustomDTO
{
    ID  = 1,
    MyPayload = 13,
    MyOtherPayload = "Test",
};
data.MyItems.Add(new MyItem { ID = 1, ParentID = 1, Name = "client", Value = 5 });
ctx.MyCustomDTOs.Add(data);
ctx.SubmitChanges();

the idea here is pretty banal – use part of Submit processing as our custom operation.

The most painful limitation of using DTOs in WCF RIA is that you can’t use DTOs as [Query] methods parameters

Code Snippet
public IQueryable<TestData> MyQuery(MyCustomDTO data)

will produce following compilation error

Parameter 'data' of domain operation entry 'MyQuery' must be one of the predefined serializable types.

Why??? Why RIA team has decided that providing only basic types as parameters would be enough? Take a look outside your Ivory Tower guys – there is real world outside and developers do need complex query parameters (you just can’t express everything with IQueryable<T> and simple typed parameters)

The workaround is as usual simple and ugly – you can expose your parameter as string, serialize your DTO on client and de-serialize on server

Code Snippet
public IQueryable<TestData> TestDataSearch(string searchCriteria)

Ok, to summarize – by now RIA has very limited support for passing DTOs back and forth. We can pray and wait for this to be fixed or use dirty workarounds.

Happy RIA coding, to be continued…

Wednesday, March 31, 2010

RIA and DTO

At the moment (RC bits) WCF RIA doesn’t support custom DTO as parameters for domain service operations. If you define

Code Snippet
[DataContract]
public class MyCustomDTO
{
    [DataMember]
    public int MyPayload { get; set; }
    [DataMember]
    public string MyOtherPayload { get; set; }
}

You won't be able to do this

Code Snippet
[Invoke]
public void MyOperation(MyCustomDTO data)

Compiler will greet you with this encouraging message:

Operation named 'MyOperation' does not conform to the required signature. Parameter types must be an entity type or one of the predefined serializable types.

Well, don’t be scared, there is workaround (as usual) to make our custom DTO “RIA friendly” (or Entity type in RIA terms).

You need to do 2 simple but not obvious things

1. Make your class identifiable by providing RIA with identity property(ies)

Code Snippet
public class MyCustomDTO
{
    [Key]
    public int MyDummyKey { get; set; }

    public int MyPayload { get; set; }
    public string MyOtherPayload { get; set; }
}

Note that we don’t need WCF data contract attributes anymore – RIA code generator takes care of it

2. Expose our “entity” via domain service dummy Query

Code Snippet
[Query]
public IQueryable<MyCustomDTO> GetMyCustomDTODummy() { return null; }

Now you can successfully compile your project and use your custom operation with custom DTO client side

Code Snippet
var ctx = (OrderContext)orderDomainDataSource.DomainContext;
var data = new MyCustomDTO
{
    MyPayload = 13,
    MyOtherPayload = "Test"
};
ctx.MyOperation(data);

but what about more complex DTOs with sub lists (data graphs)? well, just wait for the next post ;)