📜 ⬆️ ⬇️

Using Dynamic Data with Entity Framework 5



Good day!

As you know, the release version of .NET Framework 4.5 has already been released, and the final version of Visual Studio 2012 has also become available for download.
')
I managed to get acquainted with the new Visual Studio from the beta version, and after the release I started using Visual Studio and .NET Framework 4.5 rtm release in real work.
The new version of the .NET Framework also includes a new version of the Entity Framework. Already the fifth. More precisely, it does not quite go in there — when I create a project, the files are loaded from the NuGet repository. But in any case, the new project uses exactly version 5 of the library.

Before continuing, I want to briefly tell you what's new in EF5 and why I decided to start using this version.

What's new in Entity Framework 5.0



This is not a complete list, but these opportunities have interested me quite strongly.
More details about innovations can be found here .

The essence of the task


In many of my projects for data management, I use a solution based on ASP.NET Dynamic Data (how exactly this solution can be applied, and in general, tools that implement scaffolding technology — I wrote earlier ). As already mentioned, the new version of the Entity Framework, even when using Database First mode, now generates a context based on the DbContext class, rather than the ObjectContext , as it was before. Dynamic Data assumes that ObjectContext is used as the base context class.

In this regard, for the correct operation of Dynamic Data, it was necessary to slightly change the context initialization and the work of some controls. I found a very good article on this subject in the blog Pranava Rastogi ,

I think that this information is useful to those who use Dynamic Data and plans to switch to a new version of the Entity Framework.

Configuring ASP.NET Dynamic Data to interact with a DbContext based context


In order for Dynamic Data to work correctly with the new format, you need to take three simple steps.

1. Change the Global.asax code in the project root

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


2. Change the ManyToMany.ascx.cs control code in the Dynamicdata \ Fieldtemplates directory

  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 the ManyToMany_Edit.ascx.cs control code in the Dynamicdata \ Fieldtemplates directory


 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 += DataSource_UpdatingOrInserting; ds.Inserting += 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; } } 


After the changes you have made, Dynamic Data will continue to work as if nothing has happened and you can continue to enjoy the development process.



Sources


Below is a list of links on the topic of the article. I hope they will be useful.

Source: https://habr.com/ru/post/150012/


All Articles