This project is read-only.

Step-by-step instructions for using M2M with WCR RIA Services

(This information is obsolete since M2M4RIA has now been ported to OpenRiaServices, checkout OpenRiaServices.M2M)

The instructions below assume that you'll be using Entity Framework code first and DbContext. If you're using an alternative DAL, you can still use M2M4Ria but the steps marked with (*) will be slightly different.

1. Add M2M Nuget packages to your projects.
  • Add the RIAservices.M2M Nuget package to your RIA Service server project. This will also add the packages RIAServices.M2M.LinkTable, RIAServices.EntityFramework, RIAServices.T4, and FluentMetadata to your project. This package will add extensions to the FluentMetadata package that enables you to specify what your M2M associations are. Furthermore, the package will add an entity generator that integrates with RIA Services code generation framework.
  • optional: If your datamodel is defined in a different project, add the Nuget package RIAServices.M2M.LinkTable to that project as well. You'll need the generic LinkTable class provided by this package in your datamodel (I'll come to that later).
  • Add the RIAServices.M2M.Silverlight Nuget package to your Silverlight project. This package adds the Silverlight M2M view on link table entities to your Silverlight project.

2. Extend your data model with link table views.
  • Define a LinkTable entity type that connects both entity types of an M2M association. E.g., given two entity types Product and Order, you can define a link table entity as follows:
    public class ProductOrder : LinkTable<Product, Order> {}
  • Define "link table views" for your M2M associations for both entity types involved in an M2M Association. E.g., for Product and Order this will be:
    using RIAServices.M2M;
    public partial class Product
    {
        public ICollection<ProductOrder> Product_ProductOrderSet
        {
            get
            {
                return OrderSet.ProjectObject1(this, x => x.Order_ProductOrderSet);
            }
        }
    }
    public partial class Order
    {
        public ICollection<ProductOrder> Order_ProductOrderSet
        {
            get
            {
                return ProductSet.ProjectObject2(this, x => x.Product_ProductOrderSet);
            }
        }
    }
ProjectObject1 and ProjectObject2 are extension methods that project an entity type to the corresponding property of a link table entity.
  • (*) Instruct entity framework to ignore these link table views from your entity model, such that the link table entities will not be populated to your data store. E.g., by adding .Ignore expressions as in the example below:
    public class MyEFContext : DbContext
    {
        public DbSet<Product> ProductSet { get; set; }
        public DbSet<Order> OrderSet { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<Product>().HasMany(x => x.OrderSet).WithMany(x => x.ProductSet);
            modelBuilder.Entity<Product>().Ignore(x => x.Product_ProductOrderSet);
            modelBuilder.Entity<Order>().Ignore(x => x.Order_ProductOrderSet);
        }
    }

3. Configure your domain service to make use of M2M associations.
  • Configure your domain service to use the Fluent metadata API.
    [EnableClientAccess]
    [FluentMetadata(typeof(MetadataConfiguration))]
    public class MyDomainService : DbDomainService<MyEFContext>
    {
    }
  • Define a fluent metadata configuration class. E.g.,
    public class MetadataConfiguration : IFluentMetadataConfiguration
    {
        public void OnTypeCreation(MetadataContainer metadataContainer)
        {
        }
    }
  • In the OnTypeCreation method, specify your M2M association using the fluent API, e.g.,

    metadataContainer.Entity<Product>()
        .Projection(x => x.OrderSet)
            .M2M(x => x.Product_ProductOrderSet, x => x.Order_ProductOrderSet, x => x.ProductSet);
This expression specifies that the property Product_ProductOrderSet is the link table view for the property OrderSet in Product, and that Order_ProductOrderSet is the corresponding link table for property ProductSet in Order. With this information in place, the M2M entity generator is able to extend the generated entities in your Silverlight client with link table collections and with M2M views for them (i.e., the entity Product will have an M2M property OrderSet and Order will have an M2M property ProductSet).

4. Integrate M2M in your domain service
  • (*) Extend the domain service with Insert and Delete operations for your link table entities. Since link table entities are transmitted between your Silverlight client and domain service, the latter must have Insert and Delete operations defined for them. Link table entities are read-only because they consist only of a composite key (which will not change once created). For this reason, there is no Update method needed in your domain service. Moreover, since link table entities are always queried via their associated entities, there is no Query method needed for them. However, you are free to define one when needed.
    using RIAServices.M2M.DbContext;
    public void InsertProductOrder(ProductOrder ProductOrder)
    {
        var Product = ProductOrder.FetchObject1(ChangeSet, DbContext);
        var Order = ProductOrder.FetchObject2(ChangeSet, DbContext);
        Product.OrderSet.Add(Order);
        DbContext.ChangeTracker.DetectChanges();
    }

    public void DeleteProductOrder(ProductOrder ProductOrder)
    {
        var Product = ProductOrder.FetchObject1(ChangeSet, DbContext);
        var Order = ProductOrder.FetchObject2(ChangeSet, DbContext);
        DbContext.LoadM2M<Product, Order, ProductOrder>(Product, Order);
        Product.OrderSet.Remove(Order);
        DbContext.ChangeTracker.DetectChanges();
    }
FetchObject1, FetchObject2, and LoadM2M are extension methods specific for DbContext that simplify the implementation of the Insert and Delete methods.
  • (*) Make sure you include the M2M associations in the query results of your entities. E.g., add "Include" expressions to your queries, like so:
    public IQueryable<Order> GetOrderSet()
    {
        return DbContext.OrderSet.Include(x => x.ProductSet);
    }

Last edited May 10, 2014 at 9:03 PM by MdeJ, version 12

Comments

MdeJ Nov 19, 2012 at 9:44 PM 
Using model first should be straight forward (assuming you're using DbContext). Just follow the steps in this tutorial. If you're using ObjectContext, it might be a little more work, but it is similar.

cevans Aug 29, 2012 at 6:26 PM 
Do you have step-by-step instructions for Model First? I used v1 in a project sometime back and it worked very well. In v1 there was a T4 template that really did all the heavy work for me, I just had to removed that I did not want and make a couple small adjustments. I don't see that in V2. Any direction?

Thimmey Aug 14, 2012 at 9:26 AM 
Hi, I'm tryinig to use m2m4ria but I can't follow your tutorial. I'm using the Entity Framework. It generated classes for Department, BusinessUnit and DepartmentBusinessUnit. Can't I use them for your step by step guide? http://pastebin.com/jvbDfZar