【问题标题】:LINQ queries in a generic repository, LINQ to Entities does not recognize the method通用存储库中的 LINQ 查询,LINQ to Entities 无法识别该方法
【发布时间】:2012-11-26 17:19:02
【问题描述】:

我正在我的应用程序中设置一个通用存储库,但我遇到了一些 LINQ 查询问题。

对于非泛型,我会这样做:

    private IObjectSet<T> _objectSet;

    public List<int?> GetGroups()
    {
        List<object> objectGroups = new List<object>();
        List<int?> intGroups = new List<int?>();

        var r = (from n in _objectSet
                 select n.Group_ID).Distinct();

        objectGroups = r.OrderBy(n => n.Value).ToList();

        foreach (object value in objectGroups)
        {
            intGroups.Add((int?)value);
        }

        return intGroups;

    }

由于这是 T 类型的通用选项,因此在键入 "n." 时,IntelliSense 不会列出任何选项,因为 n 的类型strong> 没有明确定义(对吗?)。

这就是我目前所拥有的:

public interface IRepository<T> : IDisposable where T : class
{

    IQueryable<T> Fetch();
    IEnumerable<T> GetAll();
    IEnumerable<T> GetAll(bool activeOnly);
    IEnumerable<T> GetAll(string groupID, bool activeOnly);
    IEnumerable<T> Find(Func<T, bool> predicate);
    T Single(Func<T, bool> predicate);
    T First(Func<T, bool> predicate);
    List<int?> GetGroups();
    int Add(T entity);
    void Delete(T entity);
    void Attach(T entity);
    void SaveChanges();
    void SaveChanges(SaveOptions options);
}

public class DataRepository<T> : IRepository<T> where T : class
{



    /// <summary>
    /// The context object for the database
    /// </summary>
    private ObjectContext _context;

    private IEnumerable<T> _previousEntries;
    private string _PKName;

    /// <summary>
    /// The IObjectSet that represents the current entity.
    /// </summary>

    private IObjectSet<T> _objectSet;

    public DataRepository()
    {

        switch (typeof(T).Name)
        {
            case "CRM_Patient":
                _context = new TheseEntities();
                _PKName = "key_patient";
                break;
            case "CRM_Account":
                _context = new ThoseEntities();
                _PKName = "accountnumber";
                break;
            case "CRM_Supplier":
                _context = new OtherEntities();
                _PKName = "supplierid";
                break;
            default:
                _context = new OtherEntities();
                break;
        }

        _objectSet = _context.CreateObjectSet<T>();
        _previousEntries = this.GetAll();
    }

    /// <summary>
    /// Gets all records as an IQueryable
    /// </summary>
    /// <returns>An IQueryable object containing the results of the query</returns>

    public IQueryable<T> Fetch()
    {
        return _objectSet;
    }


    /// <summary>
    /// Gets all records as an IEnumberable
    /// </summary>
    /// <returns>An IEnumberable object containing the results of the query</returns>

    public IEnumerable<T> GetAll()
    {
        return Fetch().AsEnumerable();
    }

    /// <summary>
    /// Finds a record with the specified criteria
    /// </summary>
    /// <param name="predicate">Criteria to match on</param>
    /// <returns>A collection containing the results of the query</returns>
    public IEnumerable<T> Find(Func<T, bool> predicate)
    {
        return _objectSet.Where<T>(predicate);
    }

    public List<int?> GetGroups()
    {
        List<object> objectGroups = new List<object>();
        List<int?> intGroups = new List<int?>();

        //var r = (from n in _objectSet
        //         select n.GetType().GetProperty("Group_ID").GetValue(n, null)).Distinct();


        var r = Fetch().Select(n => n.GetType().GetProperty("Group_ID").GetValue(n, null)).Distinct();

        objectGroups = r.OrderBy(n => n.GetType().GetProperty("Value").GetValue(n, null)).ToList();

        foreach (object value in r)
        {
            intGroups.Add((int?)value);
        }

        return intGroups;

    }
    /// <summary>
    /// Gets a single record by the specified criteria (usually the unique identifier)
    /// </summary>
    /// <param name="predicate">Criteria to match on</param>
    /// <returns>A single record that matches the specified criteria</returns>
    public T Single(Func<T, bool> predicate)
    {
        return _objectSet.Single<T>(predicate);
    }

    /// <summary>
    /// The first record matching the specified criteria
    /// </summary>
    /// <param name="predicate">Criteria to match on</param>

    /// <returns>A single record containing the first record matching the specified criteria</returns>
    public T First(Func<T, bool> predicate)
    {
        return _objectSet.First<T>(predicate);
    }



    /// <summary>
    /// Deletes the specified entitiy
    /// </summary>
    /// <param name="entity">Entity to delete</param>
    /// <exception cref="ArgumentNullException"> if <paramref name="entity"/> is null</exception>
    public void Delete(T entity)
    {
        if (entity == null)
        {
            throw new ArgumentNullException("entity");
        }

        _objectSet.DeleteObject(entity);
    }



    /// <summary>
    /// Deletes records matching the specified criteria
    /// </summary>
    /// <param name="predicate">Criteria to match on</param>
    public void Delete(Func<T, bool> predicate)
    {
        IEnumerable<T> records = from x in _objectSet.Where<T>(predicate) select x;
        foreach (T record in records)
        {
            _objectSet.DeleteObject(record);
        }
    }

    /// <summary>
    /// Dispose
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }



    /// <summary>
    /// Dispose
    /// </summary>
    /// <param name="disposing">A boolean value indicating whether or not to dispose managed resources</param>
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (_context != null)
            {
                _context.Dispose();
                _context = null;
            }
        }
    }

}

不知何故,我的反射技巧似乎是在 LINQ 语句中执行的,当我为 objectGroups 赋值时,这显然会引发异常。

LINQ to Entities 无法识别方法 'System.Object GetValue(System.Object, System.Object[])' 方法,并且该方法无法转换为存储表达式。 p>

有什么想法吗?我真的需要保留存储库的通用性。我使用反射的所有方法都抛出异常......

非常感谢。

编辑:添加了存储库的大部分方法和接口。课程中可能缺少某些方法,但这样做是为了减轻阅读负担:)

【问题讨论】:

  • 这是一篇有趣的文章,解释了为什么通用存储库可能是反模式:sapiensworks.com/blog/post/2012/03/05/…
  • 您的实体是否所有都有属性Group_ID和属性Value?我想知道,因为您正试图在泛型类型上获取这些属性。您是否考虑过使用通用的基本类型而不是使用反射?顺便说一句:你真的应该使用 Expression&lt;Func&gt; 作为谓词,而不仅仅是 Func 和 LINQ to Entities。
  • 我想我会在输入存储库后从数据访问层外部执行此操作。 return _patientRepository.GetAll().Select(n => n.Group_ID).Distinct().ToList()
  • 你应该有一个常见的基本类型,如 Slauma 所示。然后将where T : class 替换为where T : baseClass,其中baseClass 是基类的名称。
  • 我对这些构建类的方式有点陌生,所以目前(因为它必须很快工作)我将把所有行都拉到一个变量中(var r = GetAll ()) 然后在 'r' 上我可以用反射做一些 LINQ。将来我一定会实现一些更可靠的东西。

标签: c# linq entity-framework-4 repository-pattern


【解决方案1】:

如何在接口中定义ValueGroupID 属性,然后让您的实体实现此接口并将其添加为通用约束?

然后您的GetGroups 方法将能够无需反射地调用这些属性。

【讨论】:

  • 我发现你可以在使用 AsEnumerable() 之后使用反射。像这样: var r = Fetch().AsEnumerable().Select(n => n.GetType().GetProperty("Group_ID").GetValue(n, null)).Distinct();我猜这是因为 LINQ 没有尝试将反射内容发送到 SQL,而是发送到列表。
  • 不推荐这样做,因为反射很慢。如果您关心性能,请尽量避免使用它..
猜你喜欢
  • 2021-11-06
相关资源
最近更新 更多