Using Dynamic Data with Entity Framework DbContext

Using Dynamic Data with Entity Framework DbContext

Rate This
  • Comments 4

In Visual Studio 2012, if you create a ADO.NET Data Model then the generated Context class derives from a type called DbContext instead of ObjectContext. DbContext is also used when you are using EntityFramework Code First

This post outlines the changes you have to do to your Dynamicdata project template if you want your context to derive from DbContext

1. Change Global.asax to get the ObjectContext

 DefaultModel.RegisterContext(() =>
            {
                return ((IObjectContextAdapter)new YourContextType()).ObjectContext;
            }, new ContextConfiguration() { ScaffoldAllTables = true });

2. Change ManyToMany.ascx.cs in the Dynamicdata\Fieldtemplates folder

protected override void OnDataBinding(EventArgs e)
        {
            base.OnDataBinding(e);
 
            object entity;
            ICustomTypeDescriptor rowDescriptor = Row as ICustomTypeDescriptor;
            if (rowDescriptor != null)
            {
                // Get the real entity from the wrapper
                entity = rowDescriptor.GetPropertyOwner(null);
            }
            else
            {
                entity = Row;
            }
 
            // Get the collection and make sure it's loaded
            var entityCollection = Column.EntityTypeProperty.GetValue(entity, null);
            var realEntityCollection = entityCollection as RelatedEnd;
            if (realEntityCollection != null && !realEntityCollection.IsLoaded)
            {
                realEntityCollection.Load();
            }
 
 
            // Bind the repeater to the list of children entities
            Repeater1.DataSource = entityCollection;
            Repeater1.DataBind();
        }
 
        public override Control DataControl
        {
            get
            {
                return Repeater1;
            }
        }

3. Change ManyToMany_Edit.ascx.cs in the Dynamicdata\Fieldtemplates folder

protected ObjectContext ObjectContext { get; set; }
 
        public void Page_Load(object sender, EventArgs e)
        {
            // Register for the DataSource's updating event
            EntityDataSource ds = (EntityDataSource)this.FindDataSourceControl();
 
            ds.ContextCreated += (_, ctxCreatedEnventArgs) => ObjectContext = ctxCreatedEnventArgs.Context;
 
            // This field template is used both for Editing and Inserting
            ds.Updating += new EventHandler<EntityDataSourceChangingEventArgs>(DataSource_UpdatingOrInserting);
            ds.Inserting += new EventHandler<EntityDataSourceChangingEventArgs>(DataSource_UpdatingOrInserting);
        }
 
        void DataSource_UpdatingOrInserting(object sender, EntityDataSourceChangingEventArgs e)
        {
            MetaTable childTable = ChildrenColumn.ChildTable;
 
            // Comments assume employee/territory for illustration, but the code is generic
            if (Mode == DataBoundControlMode.Edit)
            {
                ObjectContext.LoadProperty(e.Entity, Column.Name);
            }
 
            // Get the collection and make sure it's loaded
            dynamic entityCollection = Column.EntityTypeProperty.GetValue(e.Entity, null);
 
            // Go through all the territories (not just those for this employee)
            foreach (dynamic childEntity in childTable.GetQuery(e.Context))
            {
 
                // Check if the employee currently has this territory
                var isCurrentlyInList = ListContainsEntity(childTable, entityCollection, childEntity);
 
                // Find the checkbox for this territory, which gives us the new state
                string pkString = childTable.GetPrimaryKeyString(childEntity);
                ListItem listItem = CheckBoxList1.Items.FindByValue(pkString);
                if (listItem == null)
                    continue;
 
                // If the states differs, make the appropriate add/remove change
                if (listItem.Selected)
                {
                    if (!isCurrentlyInList)
                        entityCollection.Add(childEntity);
                }
                else
                {
                    if (isCurrentlyInList)
                        entityCollection.Remove(childEntity);
                }
            }
        }
 
        private static bool ListContainsEntity(MetaTable table, IEnumerable<object> list, object entity)
        {
            return list.Any(e => AreEntitiesEqual(table, e, entity));
        }
 
        private static bool AreEntitiesEqual(MetaTable table, object entity1, object entity2)
        {
            return Enumerable.SequenceEqual(table.GetPrimaryKeyValues(entity1), table.GetPrimaryKeyValues(entity2));
        }
 
        protected void CheckBoxList1_DataBound(object sender, EventArgs e)
        {
            MetaTable childTable = ChildrenColumn.ChildTable;
 
            // Comments assume employee/territory for illustration, but the code is generic
 
            IEnumerable<object> entityCollection = null;
 
            if (Mode == DataBoundControlMode.Edit)
            {
                object entity;
                ICustomTypeDescriptor rowDescriptor = Row as ICustomTypeDescriptor;
                if (rowDescriptor != null)
                {
                    // Get the real entity from the wrapper
                    entity = rowDescriptor.GetPropertyOwner(null);
                }
                else
                {
                    entity = Row;
                }
 
                // Get the collection of territories for this employee and make sure it's loaded
                entityCollection = (IEnumerable<object>)Column.EntityTypeProperty.GetValue(entity, null);
                var realEntityCollection = entityCollection as RelatedEnd;
                if (realEntityCollection != null && !realEntityCollection.IsLoaded)
                {
                    realEntityCollection.Load();
                }
            }
 
            // Go through all the territories (not just those for this employee)
            foreach (object childEntity in childTable.GetQuery(ObjectContext))
            {
                // Create a checkbox for it
                ListItem listItem = new ListItem(
                    childTable.GetDisplayString(childEntity),
                    childTable.GetPrimaryKeyString(childEntity));
 
                // Make it selected if the current employee has that territory
                if (Mode == DataBoundControlMode.Edit)
                {
                    listItem.Selected = ListContainsEntity(childTable, entityCollection, childEntity);
                }
 
                CheckBoxList1.Items.Add(listItem);
            }
        }
 
        public override Control DataControl
        {
            get
            {
                return CheckBoxList1;
            }
        }
 

At this point you should be good to run your application and use DbContext or EntityFramework Code First with Dynamicdata templates

Leave a Comment
  • Please add 5 and 3 and type the answer here:
  • Post
  • The .NET Web Development and Tools group shipped a Dynamic Data project template with VS2012 that hard fails on the first line of code and the failure can be fixed by a simple mod to the template.

    I guess DynamicData is a dying technology afterall. Hopefully the ASP.NET MVC team will pick it up an integrate it into ASP.NET MVC.

  • VB version of the RegisterContext call in the global.asax...

           DefaultModel.RegisterContext( _

               New System.Func(Of Object)(Function() DirectCast(New DALL(), IObjectContextAdapter).ObjectContext), _

               New ContextConfiguration() With {.ScaffoldAllTables = True} _

           )

    Where DALL() is the context object of your model.

  • Pranav

    Would you please indicate which lines you changed in the ManyToMany C# code behind files so I can make the equiv changes in the VB files.

  • @Brian, we will be fixing this issue in a future update to "Web Tools Extensions". On the bright side you will not have to wait for an update for VS to get the templates update since WebToolsExtensions carries the project templates for WebForms and we can update this at a much faster rate.

    I will be blogging a lot more on how DynamicData can be used efficiently in your application with investments in ModelBinding which makes the entire development experience better.

    For these changes, I would suggest replacing the contents of the entire file

Page 1 of 1 (4 items)