动态数据中的多对多关系

时间:2012-12-13 11:03:14

标签: c# sql dynamic-data

我刚创建了一个动态数据项目,我的数据库项目中有很多多对多的关系和元素。最大的问题是,当我想编辑/插入元素时,因为每个多对多关系都在复选框列表中“翻译”。因此,对于我想要插入/编辑它的实体,它将产生一个〜4000像素高度的页面,其中包含多对多元素。

像这样(假设我们在产品和类别之间存在多对多的关系):

 Column                             Elements


 Name                              -textbox here
 Description                       -multi-line text area here

                                   NameOfCat1(checkbox) NameOfCat2(checkbox)
                                   NameOfCat3(checkbox) NameOfCat4(checkbox)
 Categories                        NameOfCat5(checkbox) NameOfCat6(checkbox)
                                   NameOfCat7(checkbox) NameOfCat8(checkbox)
                                   NameOfCat9(checkbox) NameOfCat10(checkbox) 

我现在想的是创建一个名为“GridviewCheckboxes”的自定义字段,使用GridView加载我的实体,在其名称前面有一个复选框(因为gridview也有分页)。

我的问题是:

1)可以关注this tutorial吗?

2)如何让gridview加载我特定的多对多关系?

因为我有产品类别,但我也可以拥有汽车车库,我也可以拥有人员 - 城市等等。

1 个答案:

答案 0 :(得分:0)

这就是我目前在ManyToMany_edit.ascx.cs中所拥有的。

public void Page_Load(object sender, EventArgs e) {
    // Register for the DataSource's updating event
    EntityDataSource ds = (EntityDataSource)this.FindDataSourceControl();

    // 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

    // Get the collection of territories for this employee
    RelatedEnd entityCollection = (RelatedEnd)Column.EntityTypeProperty.GetValue(e.Entity, null);

    // In Edit mode, make sure it's loaded (doesn't make sense in Insert mode)
    if (Mode == DataBoundControlMode.Edit && !entityCollection.IsLoaded) {
        entityCollection.Load();
    }

    // Get an IList from it (i.e. the list of territories for the current employee)
    // REVIEW: we should be using EntityCollection directly, but EF doesn't have a
    // non generic type for it. They will add this in vnext
    IList entityList = ((IListSource)entityCollection).GetList();

    // Go through all the territories (not just those for this employee)
    foreach (object childEntity in childTable.GetQuery(e.Context)) {

        // Check if the employee currently has this territory
        bool isCurrentlyInList = entityList.Contains(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 gvMyGrid_DataBound(object sender, EventArgs e)
{




}

protected void CheckBoxList1_DataBound(object sender, EventArgs e) {
    MetaTable childTable = ChildrenColumn.ChildTable;

    // Comments assume employee/territory for illustration, but the code is generic

    IList entityList = null;
    ObjectContext objectContext = 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
        RelatedEnd entityCollection = Column.EntityTypeProperty.GetValue(entity, null) as RelatedEnd;
        if (entityCollection == null) {
            throw new InvalidOperationException(String.Format("The ManyToMany template does not support the collection type of the '{0}' column on the '{1}' table.", Column.Name, Table.Name));
        }
        if (!entityCollection.IsLoaded) {
            entityCollection.Load();
        }

        // Get an IList from it (i.e. the list of territories for the current employee)
        // REVIEW: we should be using EntityCollection directly, but EF doesn't have a
        // non generic type for it. They will add this in vnext
        entityList = ((IListSource)entityCollection).GetList();

        // Get the current ObjectContext
        // REVIEW: this is quite a dirty way of doing this. Look for better alternative
        ObjectQuery objectQuery = (ObjectQuery)entityCollection.GetType().GetMethod(
            "CreateSourceQuery").Invoke(entityCollection, null);
        objectContext = objectQuery.Context;
    }

    // Go through all the territories (not just those for this employee)
    foreach (object childEntity in childTable.GetQuery(objectContext)) {
        MetaTable actualTable = MetaTable.GetTable(childEntity.GetType());
        // Create a checkbox for it
        ListItem listItem = new ListItem(
            actualTable.GetDisplayString(childEntity),
            actualTable.GetPrimaryKeyString(childEntity));

        // Make it selected if the current employee has that territory
        if (Mode == DataBoundControlMode.Edit) {
            listItem.Selected = entityList.Contains(childEntity);
        }

        CheckBoxList1.Items.Add(listItem);
    }
}

public override Control DataControl {
    get {
        return gvMyGrid;
    }
}