0

我已经在我的通用 EF 存储库的 Add() 方法中实现了检查我要插入的行是否已经存在于表中,如果存在,则使用当前可用的信息对其进行更新。

private List<T> _previousEntries;

//Try and find one with same PK in the temporary tables...
var previousRow = _previousEntries.Single(n => (int)n.GetType().GetProperty(_PKName).GetValue(n, null) == entPKValue);

//If we did find one...
if (previousRow != null)
{
   //Update the row...
   return;
}

//Add it...

所以我知道,我正在使用反射,这很慢,但我还没有找到另一种方法,因为不同的实体有不同的 SQL PK 名称。

但我不确定反射是这里最大的问题,有时,_previousEntries最多可以容纳 800,000 个项目。

_previousEntries在存储库类的类构造函数中为其分配了项目。_PKName 也根据 T 的类型在类构造函数中分配一个值。

如果我只是在 Single() 语句上设置断点,它肯定会处理 2-3 秒,所以我不知道如何确定这里的瓶颈是什么:反射或 Single() 对 800,000 个项目.. . 它在 5,000 项列表上的速度肯定更快。

有什么意见吗?我可以做些什么来优化我的 List 吗?

4

3 回答 3

2

You could move the reflection out of the LINQ statement to avoid it being evaluated repeatedly:

var property = typeof(T).GetProperty(_PKName);
var previousRow = _previousEntries.Single(n => (int)property.GetValue(n, null) == entPKValue);

Or perhaps pass a Func<T, int> to your class constructor and avoid the need for reflection altogether.

private Func<T, int> _getKeyForItem; // Set by constructor
...
var previousRow = _previousEntries.Single(n => _getkeyForItem(n) == entPKValue);
于 2012-11-27T21:42:08.570 回答
1

提供主键访问器作为委托

public class Repository<T>
{
    private Funct<T,int> _getPK;
    private Dictionary<int,T> _previousEntries;

    public Repository(Funct<T,int> getPK)
    {
        _getPK = getPK;
        _previousEntries = new Dictionary<int,T>();
    }

    public void Add(T item) {
        ...
        int pk = _getPK(item);
        T previousEntry;
        if (_previousEntries.TryGetValue(pk, out previousEntry) {
            // Update
        } else {
            // Add
            _previousEntries.Add(pk, item);
        }
    }
}

您将创建一个这样的存储库

var clientRepository = new Repositiory<Client>(c => c.ClientID);
于 2012-11-27T21:49:29.870 回答
0

没有办法快速搜索未排序的列表。它将是 O(项目数)。

您需要使用其他一些数据结构来加快查找速度 - 字典或按 PK 排序的列表是可能的选项。

于 2012-11-27T21:42:55.497 回答