【问题标题】:How to perform join using an expression如何使用表达式执行连接
【发布时间】:2016-02-16 04:42:15
【问题描述】:

我正在为我的项目使用实体框架包装器。如果我只使用一个表进行 CRUD 操作,它工作正常,但不幸的是我无法连接两个表。

我看到有人建议包含我也无法使用。

reference

我也有this,但我听不懂。

我在下面分享我的 BaseRepository 类

 public class BaseRepository<T> : IBaseRepository<T> where T : class
 {
    private IUnitOfWork unitOfWork;
    private DbSet<T> dbSet;

    public BaseRepository(IUnitOfWork unitOfWork)
    {
        this.unitOfWork = unitOfWork;
        this.dbSet = unitOfWork.DbContext.Set<T>();
    }

    public virtual IEnumerable<T> Get(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "")
    {
        IQueryable<T> query = dbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        foreach (var includeProperty in includeProperties.Split
            (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }

        if (orderBy != null)
        {
            return orderBy(query).ToList();
        }
        else
        {
            return query.ToList();
        }
    }

    public virtual IEnumerable<T> Get()
    {
        return dbSet.ToList();
    }

    public virtual IEnumerable<T> Get(Expression<Func<T, bool>> predicate)
    {
        return dbSet.Where(predicate);
    }

    public virtual T Get(object id)
    {
        return dbSet.Find(id);
    }

    public virtual IQueryable<T> Where(Expression<Func<T, bool>> predicate)
    {
        return dbSet.Where(predicate);
    }

    public virtual IQueryable<T> Query()
    {
        return dbSet;
    }

    public bool Any(Expression<Func<T, bool>> predicate)
    {
        return dbSet.Any(predicate);
    }

    public T First(Expression<Func<T, bool>> predicate)
    {
        return dbSet.First(predicate);
    }

    public T FirstOrDefault(Expression<Func<T, bool>> predicate)
    {
        return dbSet.FirstOrDefault(predicate);
    }

    public virtual void Insert(T entity)
    {
        dbSet.Add(entity);
    }

    public virtual void Update(T entity)
    {

        if (unitOfWork.DbContext.Entry(entity).State == EntityState.Detached)
        {
            dbSet.Attach(entity);
        }

        unitOfWork.DbContext.Entry(entity).State = EntityState.Modified;
    }

    public virtual void Delete(object id)
    {
        T entityToDelete = dbSet.Find(id);
        Delete(entityToDelete);
    }

    public virtual void Delete(T entity)
    {
        if (unitOfWork.DbContext.Entry(entity).State == EntityState.Detached)
        {
            dbSet.Attach(entity);
        }
        dbSet.Remove(entity);
    }

    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                unitOfWork.DbContext.Dispose();
            }
        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    public IEnumerable<T> ExecWithStoreProcedure(string query, params object[] parameters)
    {
        return unitOfWork.DbContext.Database.SqlQuery<T>(query, parameters);
    }
}

请让我知道我需要在 BaseRepository 中执行哪些更改,以便我可以执行加入。

【问题讨论】:

  • 你有什么不明白的?
  • 我不明白如何封装一个复杂的查询。我想使用像 var empList = (from e in empRepository.Where(e => e.EmpID==123) join d in deptRepository在 e.DeptID 上等于 d.DeptID
  • 我从您的问题中删除了存储库模式引用,因为您不了解该模式的目的(作为持久层的抽象以降低复杂性)。任何暴露 LINQ 的类(只是包装 Linq To Sql)根本不是抽象。你仍然必须知道你的 ORM 的局限性才能使用它。您能否描述一下您的解决方案与直接使用 EF 接口相比有哪些好处?我只是没看到。接受的答案看起来与直接使用 EF 完全一样,并且清楚地说明了我的观点。

标签: asp.net-mvc entity-framework linq


【解决方案1】:

好的...所以,查看您的基础存储库,您似乎已经做好了准备。我最好的猜测是您只是对使用存储库模式感到困惑。因此,您向我们展示了采用 &lt;T&gt; 类型的 BaseRepository。您的特定存储库是如何创建的?例如,您必须拥有 AccountRepository 或 ContactRepository,它们需要在 UnitOfWork 类中使用类似这样的通用基础存储库:

private IBaseRepository<Account> _accountRepository;    
    public IBaseRepository<Account> AccountRepository
    {
        get { return _accountRepository ?? (_accountRepository = new BaseRepository<Account>(_databaseFactory)); }
    }

您可以如下调用:

private IBaseRepository<Account> accountRepo { get { return UnitOfWork.AccountRepository; } }

并像 accountRepo.Get() 一样使用它,它会为您提供所有帐户的列表。

如果这是您使用存储库的方式,那么您只需添加其他实体的存储库即可:

private IBaseRepository<Contact> contactRepo { get { return UnitOfWork.ContactRepository; } }

并执行如下加入:

return (from c in contactRepo.GetAll()
            join a in accountRepo.GetAll() on c.AccountId equals a.AccountId
            where a.Name == "Test Account Name"
            select c).ToList();

上面将为您提供属于 Name = "Test Account Name" 的帐户的所有联系人。

让我知道它是如何为你工作的。

【讨论】:

  • @Manish Kumar GetAll() 这个函数是如何定义的?,我担心GetAll() 会将整个表返回到内存中。在上述存储库模式中,Get()includeProperties 将导致 inner join
  • @Eldho 这是一个有效的担忧,但上述建议不会受到您害怕的性能问题的影响。因为,在存储库模式中,GetAll() 应按如下方式实现: public virtual IQueryable GetAll() {return _dbset;} 注意返回类型 IQueryable 不会评估查询,它将创建将执行的“可查询”查询仅在 .ToList() 之后:返回(从 c in contactRepo.GetAll() 加入 a in accountRepo.GetAll() on c.AccountId 等于 a.Id 其中 a.Id == 1 选择 c).ToList();由于 .ToList() 之前的 where 条件,只有匹配的记录才会加载到内存中。
  • 谢谢 manish,我没注意到它是 iQuerable 。感谢您的详细信息,不胜感激
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-01
相关资源
最近更新 更多