September 2010 - Posts

WP7: an application to help people with language issues

I developed a Windows Phone Seven application to help people with language issues. This application is principally useful for concerned autistic people (like my son) but it can also be used for many handicap.

You can look at the video here.

Please like the video. I need a lot of likes to be able to present it to Steve Ballmer for a Microsoft France Challenge.

Note that you first have to like developer group page http://www.facebook.com/Developpeurs.net. Then go to http://www.facebook.com/video/video.php?v=474796506010&ref=mf and like it Sourire

.

Posted by Matthieu MEZIL | with no comments
Filed under: , ,

EDM mapping: How to use Horizontal Entity Splitting

One of the reasons why I love so much Entity Framework is the mapping.

Many developers ignore how powerful EF mapping is.

I just remind them that I realized some videos on it.

Some scenarios are often very useful but some are less frequent. Horizontal Entity Splitting is one of these. However, I will try to demonstrate in this post that it can be useful in some cases.

Imagine Northwind: Products, Orders, OrderDetails. Orders and Products table have an identity primary key. OrderDetails PK is the couple ProductID, OrderID.

image

Now imagine that to have traceability I decided to implement logical deletion instead of real deletion.

In Orders and Products tables, I just have to add a not nullable bit column IsDeleted.

In my model, I add a condition IsDeleted = false to automatically filter my entities.

image

Now the problem is for OrderDetails. Indeed, the couple OrderID, ProductID now has to be unique… only when IsDeleted is false.

For this, I add a new not nullable uniqueidentifier colum OrderID with default value to NewId() and I now define the PK on it.

image

Then, I add an unicity constraint on my old pk using an unique key index:

image

Then, I use the table creation script to create a new table DeletedOrderDetails without constraint (except foreign keys):

image

CREATE TABLE [dbo].[DeletedOrderDetails](

      [OrderDetailID] [uniqueidentifier] NOT NULL,

      [OrderID] [int] NOT NULL,

      [ProductID] [int] NOT NULL,

      [UnitPrice] [money] NOT NULL,

      [Quantity] [smallint] NOT NULL,

      [Discount] [real] NOT NULL,

 CONSTRAINT [PK_DeletedOrderDetails] PRIMARY KEY CLUSTERED

(

      [OrderDetailID] ASC

)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

) ON [PRIMARY]

 

GO

 

ALTER TABLE [dbo].[DeletedOrderDetails]  WITH NOCHECK ADD  CONSTRAINT [FK_DeletedOrderDetails_Orders] FOREIGN KEY([OrderID])

REFERENCES [dbo].[Orders] ([OrderID])

GO

 

ALTER TABLE [dbo].[DeletedOrderDetails] CHECK CONSTRAINT [FK_DeletedOrderDetails_Orders]

GO

 

ALTER TABLE [dbo].[DeletedOrderDetails]  WITH NOCHECK ADD  CONSTRAINT [FK_DeletedOrderDetails_Products] FOREIGN KEY([ProductID])

REFERENCES [dbo].[Products] ([ProductID])

GO

 

ALTER TABLE [dbo].[DeletedOrderDetails] CHECK CONSTRAINT [FK_DeletedOrderDetails_Products]

GO

Then, I update my edmx from database to change my OrderDetail entity type, the [Order Details] table in the SSDL and the MSL between them.

Next, I define my OrderDetail entity type key only OrderDetailID.

image

Now, because I have different default values on my database for OrderDetailID different for each row, I can set StoreGeneratedPattern metadata to Identity for this property and this column in order to let the database generates it (note that only the StoreGeneratedPattern on SSDL is used for this case). I can do it with the designer for the property but only by modifying myself the xml for the column myself.

imageimage

What is really cool with this is the fact that I don’t have to change anything on my code. // except Delete methods.

 

 

Now, I will allow deletion.

For this, I create a new edmx NorthwindDeletion from DB with my four tables.

I want this entity model:

image[44]

For my entities, it isn’t my problem if there are some DB constraints. I want a very easy way to delete or restore an entity and having a boolean property is the best way I found.

To have this model, after creating my edmx, I delete DeletedOrderDetail entity type without deleting the table in the SSDL.

Thus, after renaming entity types and mapping OrderDetail entity type on the two OrderDetail tables, I have three entities: ProductDeletion mapped on Products, OrderDeletion mapped on Orders and OrderDetailDeletion mapped on [Order Details] AND DeletedOrderDetails.

Then I add a new not nullable bool property IsDeleted on OrderDetailDeletion entity type.

Now I have to use OrderDetailDeletion.IsDeleted property to identify the table. It is what we name Horizontal Entity Splitting. Sadly, it isn’t supported by the VS EDM designer yet. So I have to modify the xml myself:

image

And here we are. If I set OrderDetailDeletion.IsDeleted to true, it will imply a Delete From [Order Details] and an insert on DeletedOrderDetails (and reversely if OrderDetailDeletion.IsDeleted is set to false) when I will call the context SaveChanges method.

Pretty cool, isn’t it? For my part, I think that EF rocks!

EnumerableCollection

Imagine the following scenario. You use MVVM, you have two classes on your model:

public class Child
{
}
public class Parent
{
    private ObservableCollection<Child> _children;
    public ObservableCollection<Child> Children
    {
        get { return _children ?? (_children = new ObservableCollection<Child>()); }
    }
}
You have two more classes on your ViewModel:
public class ChildViewModel
{
    public ChildViewModel(Child child)
    {
        Child = child;
    }

    private Child Child { get; set; }
}
public class ParentViewModel 
{
    public ParentViewModel(Parent parent = null)
    {
        Model = parent ?? new Parent();
    }
    private Parent Model { get; set; }
    private ObservableCollection<ChildViewModel> _children;
    public ObservableCollection<ChildViewModel> Children
    {
        get { return _children ?? (_children = new ObservableCollection<ChildViewModel>(Model.Children.Select(c => new ChildViewModel(c)))); }
    }
}
Now, how to fix the the synchronization problem between the two collections?
I think that, in this case, the ViewModel should not be a collection but only an IEnumerable.
So now, you can write the following code:
public class ParentViewModel : INotifyPropertyChanged
{
    public ParentViewModel(Parent parent = null)
    {
        Model = parent ?? new Parent();
        Model.Children.CollectionChanged += delegate { RaisePropertyChanged(() => Children); };
    }
    private Parent Model { get; set; }
    public IEnumerable<ChildViewModel> Children
    {
        get { return Model.Children.Select(c => new ChildViewModel(c)); }
    }
    #region INotifyPropertyChanged Members
    public void RaisePropertyChanged<T>(Expression<Func<T>> exp)
    {
        var memberExpression = exp.Body as MemberExpression;
        if (memberExpression == null)
            return;
        string propertyName = memberExpression.Member.Name;
        if (propertyName != null && PropertyChanged != null)       
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    public event PropertyChangedEventHandler PropertyChanged;
    #endregion
}
It works. However, if you add or remove a child to Parent.Children collection, all ViewModel Children are recreated which can be a big problem with binding.
So in fact, I want an IEnumerable<T> which also implements INotifyCollectionChanged.
So I propose a new class: EnumerableCollection
public interface IEnumerableCollection<out T> : IEnumerable<T>, INotifyCollectionChanged
{
    void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e);
}

public class EnumerableCollection<T> : EnumerableCollection<T, T>
{
    public EnumerableCollection(ObservableCollection<T> observableCollection)
        : base(observableCollection, null)
    {
    }

    public EnumerableCollection(IEnumerable<ObservableCollection<T>> observableCollections)
        : base(observableCollections, null)
    {
    }

    public EnumerableCollection(params ObservableCollection<T>[] observableCollections)
        : this((IEnumerable<ObservableCollection<T>>)observableCollections)
    {
    }

    public EnumerableCollection(IEnumerable<IEnumerableCollection<T>> enumerableCollections)
        : base(enumerableCollections, null)
    {
    }

    public EnumerableCollection(params IEnumerableCollection<T>[] observableCollections)
        : this((IEnumerable<IEnumerableCollection<T>>)observableCollections)
    {
    }

    public EnumerableCollection(IEnumerable<T> enumerable)
        : base(enumerable, null)
    {
    }
}

public class EnumerableCollection<TSource, TResult> : IEnumerableCollection<TResult>, IEnumerable<TResult>, INotifyCollectionChanged
{
    private IEnumerable<TResult> _enumerable;

    #region ctors
    public EnumerableCollection(ObservableCollection<TSource> observableCollection, Func<TSource, TResult> selector)
    {
        observableCollection.CollectionChanged += (sender, e) => RaiseCollectionChanged(e);
        _enumerable = Convert(observableCollection, selector);
    }

    public EnumerableCollection(IEnumerable<ObservableCollection<TSource>> observableCollections, Func<TSource, TResult> selector)
    {
        foreach (ObservableCollection<TSource> observableCollection in observableCollections)
            observableCollection.CollectionChanged += (sender, e) => RaiseCollectionChanged(e);
        _enumerable = Convert(observableCollections.SelectMany(item => item), selector);
    }

    public EnumerableCollection(IEnumerable<IEnumerableCollection<TSource>> enumerableCollections, Func<TSource, TResult> selector)
    {
        foreach (EnumerableCollection<TSource> enumerableCollection in enumerableCollections)
            enumerableCollection.CollectionChanged += (sender, e) => RaiseCollectionChanged(e);
        _enumerable = Convert(enumerableCollections.SelectMany(item => item), selector);
    }

    public EnumerableCollection(IEnumerable<TSource> enumerable, Func<TSource, TResult> selector)
    {
        _enumerable = Convert(enumerable, selector);
    }
    #endregion ctors

    private IEnumerable<TResult> Convert(IEnumerable<TSource> source, Func<TSource, TResult> selector)
    {
        if (selector != null)
            return source.Select(selector);
        if (typeof(TSource) == typeof(TResult))
            return (IEnumerable<TResult>)source;
        throw new InvalidOperationException();
    }

    public void OrderBy<K>(Func<TResult, K> keySelector)
    {
        if (_enumerable == null)
            throw new InvalidOperationException();
        _enumerable = _enumerable.OrderBy(keySelector);
    }

    public void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (CollectionChanged != null)
            CollectionChanged(this, e);
    }

    #region IEnumerable<T> Members
    public IEnumerator<TResult> GetEnumerator()
    {
        return _enumerable.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    #endregion

    #region INotifyCollectionChanged Members
    public event NotifyCollectionChangedEventHandler CollectionChanged;
    #endregion
}
With this, my ParentViewModel code becomes this:
public class ParentViewModel
{
    public ParentViewModel(Parent parent = null)
    {
        Model = parent ?? new Parent();
    }

    private Parent Model { get; set; }

    private EnumerableCollection<Child, ChildViewModel> _children;
    public EnumerableCollection<Child, ChildViewModel> Children
    {
        get { return _children ?? (_children = new EnumerableCollection<Child, ChildViewModel>(Model.Children, c => new ChildViewModel(c))); }
    }
}
Hope that helps
Posted by Matthieu MEZIL | with no comments
Filed under: , , ,