Skip to content

Instantly share code, notes, and snippets.

@duncansmart
Forked from davidebbo/ManyToMany.ascx.cs
Created July 13, 2012 19:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save duncansmart/3106808 to your computer and use it in GitHub Desktop.
Save duncansmart/3106808 to your computer and use it in GitHub Desktop.
Dynamic Data many to many templates for EF code first
using System;
using System.ComponentModel;
using System.Web.UI;
namespace WebApplication
{
public partial class ManyToManyField : System.Web.DynamicData.FieldTemplateUserControl
{
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
var entityCollection = Column.EntityTypeProperty.GetValue(entity, null);
// Bind the repeater to the list of children entities
Repeater1.DataSource = entityCollection;
Repeater1.DataBind();
}
public override Control DataControl
{
get
{
return Repeater1;
}
}
}
}
using System;
using System.Data.Objects;
using System.ComponentModel;
using System.Collections;
using System.Linq;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.DynamicData;
using System.Collections.Generic;
namespace WebApplication
{
public partial class ManyToMany_EditField : System.Web.DynamicData.FieldTemplateUserControl
{
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 += (_, ctxCreatedEventArg) => ObjectContext = ctxCreatedEventArg.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 of territories for this employee
dynamic entityList = 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
bool isCurrentlyInList = ListContainsEntity(childTable, entityList, 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)
entityList.Add(childEntity);
}
else
{
if (isCurrentlyInList)
entityList.Remove(childEntity);
}
}
}
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> entityList = 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
entityList = (IEnumerable<object>)Column.EntityTypeProperty.GetValue(entity, null);
}
// 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, entityList, childEntity);
}
CheckBoxList1.Items.Add(listItem);
}
}
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)
{
var pks1 = table.GetPrimaryKeyValues(entity1);
var pks2 = table.GetPrimaryKeyValues(entity2);
return Enumerable.SequenceEqual(pks1, pks2);
}
public override Control DataControl
{
get
{
return CheckBoxList1;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment