0

我有一个泛型类,它对 T 类型的实体执行添加/更新。该AddOrUpdate()方法接受一个DbSet要作用的集合以及要在DbSet. 用于检查集合中ItemExists()是否已存在项目。如果是这样,我们会更新。如果没有,我们添加。该方法本质上将传入的项目的主键与表中的每个项目进行比较,如果匹配,则返回 true(以及数据库对象本身)。

该代码适用于具有少量记录的表。然而,对于较大的表,该ItemExists()方法非常低效。该方法使用一个 foreach 循环,该循环本身位于调用者方法中的另一个 foreach 循环内,给出 O(n^2)。

一种更简单的方法是简单地使用contextDataSet.Contains(item),但这会引发一个异常,说明Unable to create a constant value of type这是有道理的,因为 EF 无法将类转换为 SQL 查询。所以这是不行的。

DbSet<T>现在我的实际问题是:有没有办法用IEnumerable<T>传入的替换整个?传入的 IEnumerable 绑定到视图上的数据网格,并且基本上包括所有项目,因此从逻辑上讲,替换整个集合应该是安全的。任何帮助是极大的赞赏。

代码

public void AddOrUpdate<I, P>(Expression<Func<I, P>> dbSetExpression, IEnumerable<T> itemsToUpdate)
            where I : DbContext, new()
            where P : DbSet<T>
{
    DataFactory.PerformOperation<I>(c =>
    {
        if (m_primaryKey == null && !TryFindPrimaryKey(c))
        {
            throw new ArgumentException("Primary key cannot be null.");
        }

        // Get the table name from expression passed in.
        string dbsetName = ((MemberExpression)dbSetExpression.Body).Member.Name;

        var propertyInfo = c.GetType().GetProperties().Single(p => p.Name == dbsetName);

        // Get the values in the table.
        DbSet<T> contextDataSet = propertyInfo.GetValue(c) as DbSet<T>;


        foreach (var item in itemsToUpdate)
        {

            // If the primary key already exists, we're updating. Otherwise we're adding a new entity.
            T existingItem;

            if (ItemExists(contextDataSet, item, out existingItem) && existingItem != null)
            {
                c.Entry(existingItem).CurrentValues.SetValues(item);
            }
            else
            {
                contextDataSet.Add(item);
            }
        }

        c.SaveChanges();
    });
}

private bool ItemExists(DbSet<T> itemInDbSet, T itemInList, out T existingItem)
{
    foreach (var dbItem in itemInDbSet)
    {
        // Get the primary key value in the database.
        var dbValue = dbItem.GetType().GetProperties().Single(
            p => p.Name == m_primaryKey).GetValue(dbItem);

        // Get the primary key value from the item passed in.
        var itemValue =
            itemInList.GetType().GetProperties().Single(
            p => p.Name == m_primaryKey).GetValue(itemInList);

        // Compare the two values.
        if (dbValue.ToString() == itemValue.ToString())
        {
            existingItem = dbItem;
            return true;
        }
    }

    existingItem = null;
    return false;
}
4

0 回答 0