制作通用方法来更新实体框架的多对多导航属性

时间:2014-07-10 22:16:28

标签: c# asp.net sql-server linq entity-framework

这是一种方法,我必须以多对多关系更新单个导航属性,但它对于DAL来说太具体了。我想知道是否有人可以帮助使这个方法更通用,以便它可以处理传入的任何实体。

我会传递两个参数:要更新的实体和要修改的导航属性。

以下方法适用于涉及多对多关系的项目表和属性表。可以将项目分配给许多属性,并且属性可以包含许多项目。

感谢您提供的任何帮助。

public void UpdateItems(Property property)
        {
            using (var context = new PropertyManagementDBEntities())
            {
                var customerInDb = context.Properties.Include("Items")
                    .Single(c => c.propertyId == property.propertyId);



                // Remove types
                foreach (var itemInDb in customerInDb.Items.ToList())
                    if (!property.Items.Any(t => t.itemId == itemInDb.itemId))
                        customerInDb.Items.Remove(itemInDb);

                // Add new types
                foreach (var item in property.Items)
                    if (!customerInDb.Items.Any(t => t.itemId == item.itemId))
                    {
                        context.Items.Attach(item);
                        customerInDb.Items.Add(item);
                    }

                context.SaveChanges();
            }
        }

1 个答案:

答案 0 :(得分:2)

你可以这样做。

public void UpdateItems<TEntity,TRelated>(
    // Entity with new list of related items
    TEntity entity, 
    // Selector for the key of the entity element
    Func<TEntity,object[]> entityKeySelector,
    // Selector for the related items of the Property
    Expression<Func<TEntity,ICollection<TRelated>>> relatedItemsSelector,
    // Comparer of related items
    Func<TRelated, TRelated, bool> relatedItemsComparer)
    where TEntity : class
    where TRelated : class
{
    using (var context = new TCtx())
    {
        // get the Keys for the entity
        object[] entityKeyValues = entityKeySelector.Invoke(entity);
        // gets the entity entity from the DB
        var entityInDb = context.Set<TEntity>().Find(entityKeyValues);
        // loads the related entities from the DB
        context.Entry(entityInDb).Collection(relatedItemsSelector).Load();

        // gets the list of properties in the passed entity
        var newRelatedItems 
            = relatedItemsSelector.Compile().Invoke(entity);

        // Gets the list of properties loaded from the DB
        var relatedItemsInDb 
            = relatedItemsSelector.Compile().Invoke(entityInDb);

        // Remove related elements
        foreach (var relatedInDb in relatedItemsInDb)
            if (!newRelatedItems.Any(item => relatedItemsComparer
                 .Invoke(relatedInDb, item)))
            {
                // If the related intem in DB is not in the entity, remove it
                relatedItemsInDb.Remove(relatedInDb);
            }

        // Add new types
        foreach (var item in newRelatedItems)
            if (!relatedItemsInDb.Any(itemInDb => relatedItemsComparer
                .Invoke(itemInDb, item)))
            {
                // Attach the item to the Set
                context.Set<TRelated>().Attach(item);
                // If the related item is not in the DB add it
                relatedItemsInDb.Add(item);
            }

        context.SaveChanges();
    }
}

如果您的实体只有一个关键字段,您可以将实体密钥选择器更改为以下字段:Func<TEntity,object> entityKeySelector,这样可以更容易使用(或实现两个签名)。

例如,如果您有可以使用不同颜色的项目,则可以像这样调用它

ManyToManyHandler<MyDbContext>.UpdateItems(
    item,
    i => new object[] {i.ItemId},
    i => i.Colors,
    (c1, c2) => c1.ColorId == c2.ColorId
    );

第二次重载:

ManyToManyHandler<MyDbContext>.UpdateItems(
    item,
    i => i.ItemId,
    i => i.Colors,
    (c1, c2) => c1.ColorId == c2.ColorId
    );

注意:我使用的是ManyToManyHandler类,它是一个通用的静态类,TCtx作为泛型参数,UpdateItems作为静态方法