Friday, 24 October 2008

Dynamic Data - Hiding Tables on the Default.aspx page

This is just a write up of an answer to a question on the Dynamic Data forum, so here's the solution.

First of all we need an attribute class:

[AttributeUsage(AttributeTargets.Class)]
public class HideTableInDefaultAttribute : Attribute
{
    public Boolean Hide { get; private set; }

    public HideTableInDefaultAttribute(Boolean hide)
    {
        Hide = hide;
    }
    // this will allow us to have a default set to false
    public static HideTableInDefaultAttribute Default = 
        new HideTableInDefaultAttribute(false);
}

Listing 1 - HideTableIndefaultAttribute

And now the code in the Default.aspx:

protected void Page_Load(object sender, EventArgs e)
{
    System.Collections.IList visibleTables = Global.DefaultModel.VisibleTables;
    if (visibleTables.Count == 0)
        throw new InvalidOperationException(
            @"There are no accessible tables. 
            Make sure that at least one data model is 
            registered in Global.asax and scaffolding is 
            enabled or implement custom pages.");

    //Menu1.DataSource = visibleTables;
    //Menu1.DataBind();

    // Hiding tables
    var tablesMain = (from t in Global.DefaultModel.VisibleTables
                     where !t.Attributes.OfType<HideTableInDefaultAttribute>().
                        DefaultIfEmpty(HideTableInDefaultAttribute.Default).First().Hide
                     orderby t.DisplayName
                     select t).ToList();

    Menu1.DataSource = tablesMain;
    Menu1.DataBind();

}

Listing 2 - Default.aspx Page_Load event handler

Note in the where clause the DefaultIfEmpty which allows you to specify the default value to return if no value found. This means that you will always get a value and the default value will have the Hide property set to false because of the Default keyword in the Attribute definition.

Now some sample metadata:

// note the differance in the result of using 
// ScaffoldTable(false) over HideTableInDefault(true)
[ScaffoldTable(false)]
public partial class Category
{
}

[HideTableInDefault(true)]
public partial class EmployeeTerritory 
{
}

[HideTableInDefault(true)]
public partial class Product
{
}

Listing 3 - sample metadata

Limited Tables list from Northwind

Figure 1 - Limited Tables list from Northwind

See how the Products column has a foreign key link

Figure 2 - See how the Products column has a foreign key link

Note that the Category column has no link

Figure 3 - Note that the Category column has no link

If you look at each of the above Figures you will see the differences between a ScaffoldTable(false) and a HideTableInDefault(true). It's also worth noting that if you omit a table from the Model you either get a ForeignKey column of no column if it was a children column, so this makes using the above two methods the best way of hiding tables in the Default.aspx page.

Download Project

Note: You will need to change the Connection String in the web.config Big Grin

14 comments:

Anonymous said...

hi, do you know how to convert dreamweaver to C#?

and, how to do roll over in C#? e.g. mouse cursor roll over the buttom and a drop down box will appear.

thanks!+

Stephen J. Naughton said...

In Dreamweaver are you using a server tecnologyu like ColdFusion if not its just HTML. On my blog I'm using c# but the tecnology is ASP.Net 3.5 and c# is the language, what I sugest you do is have a look at some of the tutorial videos on http://www.asp.net/learn/

Hope this helps :D
Steve

BettaZ said...

Thanks Steve,
very great post!
but...sorry....I've a problem. This is the error that appears when I run your code into my .net 4.0 entity framework application in the last line of default.aspx page where there is Menu1.DataBind()
"The entity type VB$AnonymousType_0`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] does not belong to any registered model."
Where is my error?
Can you help me?
Thanks a lot. Betta

Stephen J. Naughton said...

This is a very old sample Betta, if you send me an e-mail to my e-mail (top right of this page) I will replay with a sample that works in DD4, I cannot supply a VB sample though sorry.

Steve :D

Stephen J. Naughton said...

Hi Betta, I have a working sample now in VS2010 DD4 I think the issue is that I also made some changes to the Default.aspx page and have not shown it here :( I will do an update today.

Steve :D

Stephen J. Naughton said...

Hi Betta, I've updated the article now.

Steve :D

BettaZ said...

Thaaaaaaaaaannnnnnnnnnnkkkkkkkkkkkkkkkkkkkksssssssssssssssss Steeeeeeveeeeeeeeeeeeeeeeeeeeeeee
you have made me happy!!!!!!
all work fine now.
you are a great man!!!
If you have made other fine samples about dd4 or mvc2 I'll be happy to see its. Write to me where I can find your fantastic samples. Tanks another time. Betta

Stephen J. Naughton said...

Your morethan welcome Betta :)

Steve :D

Anonymous said...

Steve,

I was having problems with the hiding the tables using your code in 4.0.

I got around the issues by creating a predicate.

private static bool FindVisible(MetaTable mt)
{
return !mt.Attributes.OfType().
DefaultIfEmpty(HideTableInDefaultAttribute.Default).First().Hide;
}

I then changed the first line of the page_load to :
System.Collections.IList visibleTables = ASP.global_asax.DefaultModel.VisibleTables.FindAll(FindVisible);

and left the Menu1.DataSource = visibleTables;

it all works now. could have never made it this far without your help. Thanks!
Mark

Stephen J. Naughton said...

Hi Mark much has changed in DD since I wrote this post and I have moved on to using a MetaDataSiteMapProvider to use a menu system on my current sites.

Steve

DriveU said...

Steve,
I have Questions a bundle of them
1. My Table Names have a Prefix when the names appear in the Menu looks weird Is their anyway to Alias them with something that is more readable?

2. How to Add a Browse button with the field where I plan to store the Path Name?

3. I am hiding a few tables which are more related to the Admin rather then the regular user. How can I show the hidden tables when I go the Admin Menu?

Stephen J. Naughton said...

Hi there, in answer to your questions;
1. Have a look at my article here Dynamic Data – Custom Metadata Providers you couls adapt this to remove the prefixes automatically by adding you own DisplayName attribute at runtime.
2. Not sure what you mean here.
3. See Securing Dynamic Data 4

Anonymous said...

Several years after the post and it's still saving people like me. Nice job.

Stephen J. Naughton said...

Thanks, I will have a new open source project soon with a new project template and ALL my bits consolidated in it.

steve