【问题标题】:Linq to SQL Repository ~theory~ - Generic but now uses Linq to Objects?Linq to SQL Repository ~theory~ - 通用但现在使用 Linq to Objects?
【发布时间】:2014-08-11 20:25:11
【问题描述】:

我目前从事的项目使用 Linq to SQL 作为一种 ORM 数据访问技术。它是一个 MVC3 Web 应用程序。我面临的问题主要是由于无法模拟(用于测试)由 DBML 设计器自动生成的 DataContext。

所以为了解决这个问题(经过大量阅读),我重构了现有的存储库系统 - 单个存储库,每个表都有单独和重复的访问方法,最终有 300 种方法,其中只有 10 种是唯一的 - 成具有通用方法的单个存储库获取表并将更多通用类型返回到应用程序的上游。 DataContext 现在已被包装,并且可以轻松模拟。

[编辑:为了实现这一点,巧合的是,我使用了下面 Jacob 提供的链接!]

我的问题更多地围绕着我迄今为止所使用的设计以及我在应用程序结构中注意到的差异。

1) 重构了使用经典 Linq to SQL 查询的代码:

    public Billing GetBilling(int id)
    {
        var result = (
        from bil in _bicDc.Billings
        where bil.BillingId == id
        select bil).SingleOrDefault();
        return (result);
    }

现在看起来像:

    public T GetRecordWhere<T>(Expression<Func<T, bool>> predicate) where T : class
    {
        T result;
        try
        {
            result = _dataContext.GetTable<T>().Where(predicate).SingleOrDefault();
        }
        catch (Exception ex)
        {
            throw ex;
        }
        return result;
    }

控制器使用如下查询:

_repository.GetRecordWhere<Billing>(x => x.BillingId == 1);

这很好,正是我想要实现的目标。

...但是....我还必须执行以下操作才能准确获得控制器类中所需的结果集(本质上是应用程序的最高点)...

viewModel.RecentRequests = _model.GetAllRecordsWhere<Billing>(x => x.BillingId == 1)
                .Where(x => x.BillingId == Convert.ToInt32(BillingType.Submitted))
                .OrderByDescending(x => x.DateCreated).
                Take(5).ToList();

这 - 据我的理解是正确的 - 现在使用 Linq to Objects 而不是我以前使用的 Linq to SQL 查询?这可以练习吗?我感觉不对,但我不知道为什么。可能是因为查询的逻辑位于应用程序的最高层,而不是最低层,但是……我听从各位好人的建议。我考虑的问题之一是将整个表放入内存,但我知道使用 Iqeryable 返回类型会将 where 子句带到数据库并在那里进行评估。因此只返回我需要的结果集......我可能是错的。

如果你已经做到了这一步,那就太好了。谢谢,如果您有任何建议,非常感谢!

更新:根据要求包含 GetAllRecordsWhere 方法

    public IQueryable<T> GetAllRecordsWhere<T>(Expression<Func<T, bool>> predicate) where T : class
    {
        return _dataContext.GetTable<T>().Where(predicate);
    }

使用:

    public IQueryable<TName> GetTable<TName>() where TName : class
    {
        return _db.GetTable<TName>().AsQueryable();
    }

【问题讨论】:

  • GetAllRecordWhere 返回什么?应该是IQueryable&lt;T&gt;
  • 它确实是一个 IQueryable,正如我在帖子末尾提到的那样 - 我相信我在某处读到过使用 IQueryable 调用的后续 .Where(predicate) 等调用在调用时会被评估而不是将很多东西拉入记忆?不管这是不是真的……
  • 只是吹毛求疵:GetRecordWhere 中的 try-catch 是多余的 - 是否已为示例进行了简化?同样,如果GetAllRecordsWhere 照它说的做,` 那么 .Where(x => x.BillingId == Convert.ToInt32(BillingType.Submitted)) 行就相当于.Where(x =&gt; 1 == Convert.ToInt32(BillingType.Submitted)) - 对吗?
  • @saus 正确,在这两个方面。
  • 您可能需要发布您的 GetAllRecordsWhere 的签名。是 Expression> 还是 Func 如果是后者,那么 LINQ to Objects 将被使用,因为接受 Func 的 Where 版本扩展了 IEnumerable,而不是 IQueryable .

标签: c# linq-to-sql linq-to-objects


【解决方案1】:

如果_model.GetAllRecordsWhere 返回一个 IQueryable,那么您的后续查询仍然只是构建一个表达式树(我认为您使用 LinqToSql 的意思是),它只会在您通过迭代枚举集合时变成 SQL 并执行在它上面或调用 ToList() 或 ToArray()。

顺便说一句,不要这样做:

catch (Exception ex)
{
    throw ex;
}

您所做的只是吞下堆栈跟踪。如果你想重新抛出异常,只需调用throw,不要调用throw ex。如果您在接球中除了重新投掷之外没有做任何事情,那么就不要接球。现在的模式是捕获,做一些记录,重新抛出。

【讨论】:

  • 它现在由专门的异常管理器处理,被处理并写入文件和数据库,所以谢谢,但它只是示例代码!不过,关于表达式树的好点。这就是我要去的地方。我试图了解我对通用存储库的实现是否正确。 (它有效,但它是正确的......?)
【解决方案2】:

如果您想模拟数据库上下文,请参阅:

http://andrewtokeley.net/archive/2008/07/06/mocking-linq-to-sql-datacontext.aspx

【讨论】:

  • 这确实是我已经实现的,但不是我的问题的主题。抱歉,如果不清楚。一个很好的链接!
【解决方案3】:

这是一篇很好的文章,解释了如何模拟您的 DataContext:

Faking your LINQ provider part 1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-03
    • 1970-01-01
    • 2011-10-22
    • 1970-01-01
    • 2019-03-20
    相关资源
    最近更新 更多