locked
Can't find my datacontext in custom fieldtemplate RRS feed

  • Question

  • User-388991285 posted

    I am trying to implement sjnaughton's ChildrenGrid (a Dynamic Data FieldTemplate that displays foreign key child rows...) ... I am having problems at runtime, though. The following call in my code:


    table = GridDataSource.GetTable();

    Is failing with the error: System.Web.HttpException: Could not load type 'ModelDataContext'.

    ModelDataContext is indeed the name of my .dbml file... I can declare a local instance of this class and that works fine,something like

    var t = new ModelDataContext();

    No exception. And the rest of my Dynamic Data classes work fine. I am trying to get the table from a griddatasource, and I know I am setting the context properly on this line

    GridDataSource.ContextTypeName = metaChildColumn.ChildTable.DataContextType.Name;


    I have debugged and the string is set to "ModelDataContext" just fine. I tried appending the full namespace for my context, like "MyApp.App_Code.ModelDataContext", but then I get an ambiguous assembly name... but I only have one ModelDAtaContext... I cleaned out my project, deleted ASP.NET temp folder files, etc. Still, no dice. Here is the code in full context:

    using System;
    using System.Data;
    using System.Configuration;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Linq;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    using System.Xml.Linq;
    using System.Web.DynamicData;
    using System.Collections.Generic;
    
    namespace NBAdminPanel.DynamicData.FieldTemplates
    {
        public partial class ChildrenGrid2_EditField : FieldTemplateUserControl
        {
            protected MetaTable table;
    
            public Boolean EnableDelete { get; set; }
            public Boolean EnableInsert { get; set; }
            public Boolean EnableUpdate { get; set; }
    
            private String[] DisplayColumns { get; set; }
    
            public ChildrenGrid2_EditField()
            {
                // set default values
                EnableDelete = true;
                EnableUpdate = true;
            }
    
            protected void Page_Init(object sender, EventArgs e)
            {
                var metaChildColumn = Column as MetaChildrenColumn;
                var attribute = Column.Attributes.OfType<NBAdminPanel.App_Code.ShowColumnsAttribute>().SingleOrDefault();
    
                if (attribute != null)
                {
                    if (!attribute.EnableDelete)
                        EnableDelete = false;
                    if (!attribute.EnableUpdate)
                        EnableUpdate = false;
                    if (attribute.DisplayColumns.Length > 0)
                        DisplayColumns = attribute.DisplayColumns;
                }
    
                var metaForeignKeyColumn = metaChildColumn.ColumnInOtherTable as MetaForeignKeyColumn;
    
                if (metaChildColumn != null && metaForeignKeyColumn != null)
                {
                    GridDataSource.ContextTypeName = metaChildColumn.ChildTable.DataContextType.Name;
                    GridDataSource.TableName = metaChildColumn.ChildTable.Name;
    
                    // enable update, delete and insert
                    GridDataSource.EnableDelete = EnableDelete;
                    GridDataSource.EnableInsert = EnableInsert;
                    GridDataSource.EnableUpdate = EnableUpdate;
                    GridView1.AutoGenerateDeleteButton = EnableDelete;
                    GridView1.AutoGenerateEditButton = EnableUpdate;
    
                    // get an instance of the MetaTable
                    table = GridDataSource.GetTable();
    
                    // Generate the columns as we can't rely on 
                    // DynamicDataManager to do it for us.
                    GridView1.ColumnsGenerator = new NBAdminPanel.App_Code.FieldTemplateRowGenerator(table, DisplayColumns);
    
                    // setup the GridView's DataKeys
                    String[] keys = new String[metaChildColumn.ChildTable.PrimaryKeyColumns.Count];
                    int i = 0;
                    foreach (var keyColumn in metaChildColumn.ChildTable.PrimaryKeyColumns)
                    {
                        keys[i] = keyColumn.Name;
                        i++;
                    }
                    GridView1.DataKeyNames = keys;
    
                    GridDataSource.AutoGenerateWhereClause = true;
                }
                else
                {
                    // throw an error if set on column other than MetaChildrenColumns
                    throw new InvalidOperationException("The GridView FieldTemplate can only be used with MetaChildrenColumns");
                }
            }
    
            protected override void OnDataBinding(EventArgs e)
            {
                base.OnDataBinding(e);
    
                var metaChildrenColumn = Column as MetaChildrenColumn;
                var metaForeignKeyColumn = metaChildrenColumn.ColumnInOtherTable as MetaForeignKeyColumn;
    
                // get the association attributes associated with MetaChildrenColumns
                var association = metaChildrenColumn.Attributes.
                    OfType<System.Data.Linq.Mapping.AssociationAttribute>().FirstOrDefault();
    
                if (metaForeignKeyColumn != null && association != null)
                {
                    // get keys ThisKey and OtherKey into Pairs
                    var keys = new Dictionary<String, String>();
                    var seperator = new char[] { ',' };
                    var thisKeys = association.ThisKey.Split(seperator);
                    var otherKeys = association.OtherKey.Split(seperator);
                    for (int i = 0; i < thisKeys.Length; i++)
                    {
                        keys.Add(otherKeys[i], thisKeys[i]);
                    }
    
                    // setup the where clause 
                    // support composite foreign keys
                    foreach (String fkName in metaForeignKeyColumn.ForeignKeyNames)
                    {
                        // get the current pk column
                        var fkColumn = metaChildrenColumn.ChildTable.GetColumn(fkName);
    
                        // setup parameter
                        var param = new Parameter();
                        param.Name = fkColumn.Name;
                        param.Type = fkColumn.TypeCode;
    
                        // get the PK value for this FK column using the fk pk pairs
                        param.DefaultValue = Request.QueryString[keys[fkName]];
    
                        // add the where clause
                        GridDataSource.WhereParameters.Add(param);
                    }
                }
                // doing the work of this above because we can't
                // set the DynamicDataManager table or where values
                //DynamicDataManager1.RegisterControl(GridView1, false);
            }
        }
    }
    





                    GridDataSource.ContextTypeName = metaChildColumn.ChildTable.DataContextType.Name;




    Tuesday, August 24, 2010 3:59 PM

Answers

  • User-330204900 posted

    Hi Richthofen, I'll get my new sample up on my blog as soon as I return from my trip and post it here also. you can then compare and see what is different.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, August 25, 2010 4:49 PM
  • User-388991285 posted

    It was indeed a project issue. The problem was that I had a Web Application Project, but put a number of my files in the App_Code folder. Subsequently the assemblies were somehow built twice. 

    Renamed the Namespaces and the App_Code folder and things are working better for the 'could not load type' error

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, October 31, 2010 2:55 PM

All replies

  • User-330204900 posted

    Hi Richthofen, what version of DD are you using DD1 and VS2008 .Net 3.5 SP1 or DD4 and VS2010 .Net 4?

    Tuesday, August 24, 2010 6:59 PM
  • User-388991285 posted

    Data Director 4 / NET 4.0 / Visual Studio 2010

    Tuesday, August 24, 2010 8:01 PM
  • User-330204900 posted

    Hi Richthofen, the good news is I have a new version nearly ready to publish on my blog for DD4 and L2S (Linq to SQL) and EF (Entity Framework), but the bad news is I am about to go away so I wont have time to publish it on my blog untill I get back sorry. Also I hope to have it working with the WCF RIA Services Domain Service project.

    Wednesday, August 25, 2010 5:04 AM
  • User-388991285 posted

    Obviously a solution to this issue would be nice, but I'm more interested in figuring out why the data context cannot be loaded. I don't see any reason why the code above shouldn't work out of the box, so to speak. The Type is available at runtime in the custom FieldTemplate itself; does the GetTable method somehow not have the appropriate scope or access inside of the method? 

    I guess I'd just like to know what's going on behind the scenes. Did the GetTable method somehow change in Data Director .NET 4 and now no longer works?

    Wednesday, August 25, 2010 9:31 AM
  • User-330204900 posted

    I know I had several errors converting to work with EF and ended up finding a way to make it generic, one thing I did find was that the Row is not actually that it is the row entity wrapped in some EF wrapper. 

    Wednesday, August 25, 2010 1:06 PM
  • User-388991285 posted

    Yeah, see, I have a feeling I will continue to have this problem even with a 'fix'. I am using LINQ-TO-SQL Classes in my project. I think it has to do with the original code you wrote being for a Web Site, and my project being a Web Application. I tried converting and making namespaces but no dice. Created a new FieldTemplate from VS using 'Add New Item' -> FieldTemplate Control. Pasted the ascx code and class code from your example... tried setting the LinqDataSource's ContextName manually in the ascx markup and that also fails. I have a feeling its something to do with my project / namespaces and not necessarily the C# code behind your example.

    Wednesday, August 25, 2010 1:16 PM
  • User-388991285 posted

    Ah-hah. So I made it deeper down the rabbit hole. 

    To make ABSOLUTELY sure that my DataContext object was available, I declared it by full assembly name (which shouldn't be required at all! but it is, for some reason)

      GridDataSource.ContextTypeName = "MyApp.App_Code." + metaChildColumn.ChildTable.DataContextType.Name + ", MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
                   

    Now I get an error which I at least understand, but can't really fix.

    Could not find a property or field called 'Additional Info' on the data context type 'ModelDataContext' of LinqDataSource 'GridDataSource'.

    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

    Exception Details: System.InvalidOperationException: Could not find a property or field called 'Additional Info' on the data context type 'ModelDataContext' of LinqDataSource 'GridDataSource

    This at least makes sense; Its looking for a field called Additional Info, but the actual field in the LinqToSql Class is AdditionalInfo, no space. The MetaDataType renames the column as a friendly name; and that's what it's barfing on. So my guess is by declaring the data context by fully qualified assembly, we are bypassing the partial class declaration in the metadata somehow? And that's blowing the whole thing to shit.

    Any insight would be appreciated.

    Wednesday, August 25, 2010 4:28 PM
  • User-330204900 posted

    Hi Richthofen, I'll get my new sample up on my blog as soon as I return from my trip and post it here also. you can then compare and see what is different.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, August 25, 2010 4:49 PM
  • User-388991285 posted

    Thanks sjnaughton. I'm still posting to this thread to see if anyone else knows what's up, because I think this is a broader DD/.NET question and less related to your very helpful control examples. 


    Really confusing is this:

                Type t = Type.GetType("ModelDataContext");
                Type g = typeof(ModelDataContext);


    Variable 't' is null. Variable 'g' is the correct type. So confusing!!!! Maybe it's a bug in .NET 



    Wednesday, August 25, 2010 8:16 PM
  • User-330204900 posted

    Maybe it's a bug in .NET 
     

    It's very rare in that sort of area, nearly all my "bugs" like that turn out to be me not undestanding the things [:$]

    I'm sure someone who knows will pipe up and tell us what's wrong here [:)]

    Thursday, August 26, 2010 3:45 AM
  • User-388991285 posted

    With regards to my post that had the 'Invalid Operation Exception' where 'Could not find a property or field called 'Additional Info''

    Changing the line 

    GridDataSource.TableName = metaChildColumn.ChildTable.Name;

    to

    GridDataSource.TableName = metaChildColumn.ChildTable.DataContextPropertyName;

    helped a long way (the table had a friendly name and the ChildTable.Name is somehow giving the table its friendlyname).

    Of course, now I'm getting other errors, but making slow progress.

    Monday, September 20, 2010 12:17 PM
  • User-330204900 posted

    Is failing with the error: System.Web.HttpException: Could not load type 'ModelDataContext'.

     

    This seems to be an issue with the project, try creating a new project and starting again.

    Tuesday, September 21, 2010 7:47 AM
  • User-388991285 posted

    I will try to recreate the project. for now, fully qualifying the assembly works. But of course, it seems that the ChildrenGrid doesn't work in Dynamic Data 4. I made some changes that seemed to be required for Dynamic Data 4, such as changing the following lines in the Page_Init of the ChildrenGrid_Edit.aspx :

    GridDataSource.ContextTypeName = metaChildColumn.ChildTable.DataContextType.FullName;// +", NBAdminPanel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
                    GridDataSource.TableName = metaChildColumn.ChildTable.DataContextPropertyName;

    GridDataSource.ContextTypeName = metaChildColumn.ChildTable.DataContextType.FullName;

    GridDataSource.TableName = metaChildColumn.ChildTable.DataContextPropertyName;

    The problem I'm seeing is that at some point (unknown because I can't set a breakpoint in the DynamicDataManager code) the MetaTable gets changed back to the Parent table and not the child table. So , on Page_Init() we are able to find the proper child table; and we configure the columns collection of the child table. But then later when the AutoGenerateColumns fires in the GridView; it seems to try and populate the dynamic controls using a reference to the parent table. It must be a change in Dynamic Data 4 as to when the MetaTable gets set on the FieldControl. I know you had said you updated the control, can you provide insight? I was hoping to learn how this all worked so I didn't have to keep bugging you.

    Thanks

    Tuesday, September 21, 2010 2:45 PM
  • User-330204900 posted

    Hi Richthofen, Like I said last time we spoke I'm working on a version for DD4 now. and will publish it as soon as I get a change [:)] too busy with a Telerik RadGrid issue in DD at the moment.

    Tuesday, September 21, 2010 6:05 PM
  • User-388991285 posted

    It was indeed a project issue. The problem was that I had a Web Application Project, but put a number of my files in the App_Code folder. Subsequently the assemblies were somehow built twice. 

    Renamed the Namespaces and the App_Code folder and things are working better for the 'could not load type' error

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, October 31, 2010 2:55 PM
  • User158460695 posted

    this worked for me... it may help others:

    Type dataContextType = Table.DataContextType;
    MyLinqDataSource.ContextTypeName = String.Format("{0}.{1}", dataContextType.Namespace.ToString(), dataContextType.Name.ToString());

    Saturday, September 1, 2012 9:13 AM