Wednesday, May 4, 2011

Why aren’t my ForeignKeys being loaded on my Custom Dynamic Data page?

This is one entry in a series of blog entries:

If you look at Part I and Part II, you may have noticed that the Product Category is a textfield when it should be a Drop Down List of the Product Categories. If this were a page that was in the DynamicData\CustomPages directory then you would not be having this problem. The reason we are having this problem is because we are calling EnableDynamicData() on our FormView which is great to get basic dynamic data functionality, but it doesn’t know how to load all the metadata for the Product entity. If you debug you will see that the ProductCategory DynamicControl column is not of type MetaForeignKeyColumn. After futher debugging you will see that much of the other metadata from the model is actually missing as well. Thankfully, the fix is very easy.

Change from:

protected void Page_Init(object sender, EventArgs e)
{
     FormView1.EnableDynamicData(typeof(MyDynamicDataExample.Models.Product));
}

to this:

protected void Page_Init(object sender, EventArgs e)
{
    // to get all the goodness like foreign-keys, etc we need to tell it to use our model
    FormView1.SetMetaTable(Global.DefaultModel.GetTable(typeof(MyDynamicDataExample.Models.Product)));
}

Also, from what I can tell the AutoLoadForeignKeys=”true” attribute of the DynamicDataManager has no bearing on whether the Drop Down List is populated or not.

You may have also noticed that the ProductCategory field when in ReadOnly mode shows a link with an number showing instead of the nice text description of the product category.  Luckily, this is an easy fix as well. In the AWDomainService.cs find we need to change the GetProducts() method to include the ProductCategory navigation property. This will cause the SQL that is generated to bring in the ProductCategory table.

Change from:

public IQueryable<Product> GetProducts()
{
    return this.ObjectContext.Products.OrderBy(o => o.Name);
}

to this:

public IQueryable<Product> GetProducts()
{
    return this.ObjectContext.Products.Include("ProductCategory").OrderBy(o => o.Name);
}

The change above will do the trick. However, if you are using this Domain Service with a Silverlight Client, you should also update the AWDomainService.metadata.cs such that the ProductCategory property on the ProductMetadata class has the Include() attribute. If you don’t have both of these Silverlight will not populate the ComboBox (assuming that is what you are using in Silverlight).

Change from:

[Display(Name = "Product Category")]
public ProductCategory ProductCategory { get; set; }

to this:

[Include()]
[Display(Name = "Product Category")]
public ProductCategory ProductCategory { get; set; }

You can download the complete source here.

No comments: