Sunday 7 December 2008

Dynamic Data – Registering Multiple Models

There are two way to get multiple model into your site:

  1. Register Multiple DataContexts with the default Model.
  2. Register each DataContext with it’s own Model.

My Models:

ScreenShot149

Register Multiple DataContexts with the default Model.

This is the simplest approach you have multiple EDMX or DBML files, all you need to do is lines like so in the Global.ascx file:

model.RegisterContext(typeof(Table1DataContext), 
    new ContextConfiguration() { ScaffoldAllTables = true });
model.RegisterContext(typeof(Table2DataContext), 
    new ContextConfiguration() { ScaffoldAllTables = true });

Listing 1 – Adding a Context to the Model

Note: you are adding the DataContext/ObjectContext to the existing model

ScreenShot148

Figure 1 – Both Contexts in one model.

Register each DataContext with it’s own Model.

This is slightly more work, you are basically duplicating each line of code for one model to two.

public static void RegisterRoutes(RouteCollection routes)
{
    // Model1 ======================================================
    MetaModel model = new MetaModel();

    model.RegisterContext(typeof(Table1DataContext),
         new ContextConfiguration() { ScaffoldAllTables = true });

    routes.Add(new DynamicDataRoute("{table}/{action}.aspx")
    {
        Constraints = new RouteValueDictionary(new { action = "List|Details|Edit|Insert" }),
        Model = model
    });

    // Model2 ======================================================
    MetaModel model1 = new MetaModel();

    model1.RegisterContext(typeof(Table2DataContext),
        new ContextConfiguration() { ScaffoldAllTables = true });

    routes.Add(new DynamicDataRoute("Model1/{table}/{action}.aspx")
    {
        Constraints = new RouteValueDictionary(new { action = "List|Details|Edit|Insert" }),
        Model = model1
    });
}

Listing 2 – Creating multiple models

Note: See the DynamicDataRoute("Model1/{table}/{action}.aspx") it is important that you differentiate the route in some way especially if some of the tables are the same name.

ScreenShot150

Figure 2  - Model route

 ScreenShot151

Figure 3  - Model1 route

As you can see from Figures 1 & 2 just by adding a differentiating route you can guarantee that there will be no table name conflicts between you models.

That get your Models registered now how to access them:

<h2>My first set of tables</h2>

<br /><br />

<asp:GridView ID="Menu1" runat="server" AutoGenerateColumns="false"
    CssClass="gridview" AlternatingRowStyle-CssClass="even">
    <Columns>
        <asp:TemplateField HeaderText="Table Name" SortExpression="TableName">
            <ItemTemplate>
                <asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl='<%#Eval("ListActionPath") %>'><%#Eval("DisplayName") %></asp:HyperLink>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>
<br /><br />

<h2>My Second set of tables</h2>

<br /><br />

<asp:GridView ID="Menu2" runat="server" AutoGenerateColumns="false"
    CssClass="gridview" AlternatingRowStyle-CssClass="even">
    <Columns>
        <asp:TemplateField HeaderText="Table Name" SortExpression="TableName">
            <ItemTemplate>
                <asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl='<%#Eval("ListActionPath") %>'><%#Eval("DisplayName") %></asp:HyperLink>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

Listing 3 – Add a second Menu to the Default.aspx

protected void Page_Load(object sender, EventArgs e)
{
    // Model 1
    System.Collections.IList visibleTables = 
MetaModel.Default.VisibleTables;
if (visibleTables.Count == 0) { throw new InvalidOperationException("There are no accessible tables."); } Menu1.DataSource = visibleTables; Menu1.DataBind(); // Model 2 System.Collections.IList visibleTables2 =
MetaModel.GetModel(typeof(Table2DataContext)).VisibleTables;
if (visibleTables.Count == 0) { throw new InvalidOperationException("There are no accessible tables."); } Menu2.DataSource = visibleTables2; Menu2.DataBind(); }

Listing 4 – Default.aspx.cs code behind

Model 1 is normal but Model 2 you are required to get the model using GetModel(typeof(DataContextName)) so what you should now see when you run the site is:

ScreenShot147

Figure 2 – Both Models shown


I know this is simple stuff and I know I have answered questions be for butI found I hadn’t an article on my blog smile_teeth

And here’s the download

Tuesday 2 December 2008

Dynamic Data - Updated URL FieldTemplate

Sorry I’ve been quiet for such a long time but towards the end of October I was helping out with a local charity and in early November I started some Freelance Web Development in DD, so from now on the posts will still come but will be a bit more infrequent (except when there is some new stuff to get our teeth into)

So improving the Url FieldTemplate, here’s what you see if you use the URL FieldTemplate as is from DD Futures:

ScreenShot004

Figure 1 – Standard Url FieldTemplate

And here’s what I want to see

ScreenShot142

Figure 2 – Improved Url FieldTemplate

Here’s the code:

<%@ Control 
    Language="C#" 
    CodeFile="Url.ascx.cs" 
    Inherits="Url" %>

<asp:HyperLink 
    ID="HyperLinkUrl" 
    runat="server" 
    Target="_blank" />

Listing 1 – Url.ascx file

public partial class Url : System.Web.DynamicData.FieldTemplateUserControl
{
    protected override void OnDataBinding(EventArgs e)
    {
        string url = FieldValueString;
        if (!(url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || 
url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))) { url = "http://" + url; } HyperLinkUrl.NavigateUrl = url; // set display text of the url HyperLinkUrl.Text = String.IsNullOrEmpty(Column.GetUrl())?
FieldValueString : Column.GetUrl(); } public override Control DataControl { get { return HyperLinkUrl; } } }

Listing 2 – Url.ascx.cs file

public class UrlAttribute : Attribute
{
    public String Text { get; private set; }

    public UrlAttribute(string text)
    {
        Text = text;
    }
    public static UrlAttribute Default = new UrlAttribute(String.Empty);
}

public static partial class HelperExtansionMethods
{
    public static String GetUrl(this MetaColumn column)
    {
        return column.Attributes.OfType<UrlAttribute>().DefaultIfEmpty(UrlAttribute.Default).First().Text;
    }
}

Listing 3 – UrlAttribute and Helper method.

[Url("Insert New Products")]
public Object InsertProducts

Listing 4 – Sample use of attributes

Now if there’s no UrlAttribute then you get the standard format but when there is a UrlAttribute present then you get the display text of  the HyperLink as that of the UrlAttribute.

I though in a future article I could assign the display text of the Url FieldTemplate to another field thus making it a bit more dynamic, but that’s for another time.