c# - 使用存储库和工作单元查询 EF 5.0

标签 c# entity-framework repository

我从事一个项目已有一段时间了。最初,我在一些书籍和网络文章中看到了一堆模式,然后花了很多时间来规划程序的架构。我决定组合 EF 5.0 > 存储库/工作单元 > MVVM > WPF。

我的初始测试表明它看起来工作得很好,所以我致力于我决定的模式,并花了一个月的时间来实现它。只是现在我快完成了,我遇到了一些麻烦。

我无法解决的问题之一是我似乎无法构造复杂的查询。无论我尝试什么,我都会遇到一个或另一个错误。

该程序使用 Entity Framework 5.0 连接到我们公司的 MS Sql 2005 Server 上的数据库。从那里开始,对于每个实体,都存在一个存储库类。每个存储库在其构造函数中接收一个上下文,并实现一个标准接口(interface):

interface IRepository<T> where T : class
{
    IEnumerable<T> GetAll();
    IEnumerable<T> Query(Expression<Func<T, bool>> filter);
    void Add(T entity);
    void Remove(T entity);
}

基类看起来像:

public abstract class Repository<T> : IRepository<T> where T : class
{
    protected IObjectSet<T> _objectSet;

    public Repository(ObjectContext context)
    {
        _objectSet = context.CreateObjectSet<T>();
    }

    public IEnumerable<T> GetAll()
    {
        return _objectSet;
    }

    public List<T> ToList()
    {
        return _objectSet.ToList<T>();
    }

    public IEnumerable<T> Query(Expression<Func<T, bool>> filter)
    {
        return _objectSet.Where(filter);
    }

    public void Add(T entity)
    {
        _objectSet.AddObject(entity);
    }

    public void Remove(T entity)
    {
        _objectSet.DeleteObject(entity);
    }

    public void Update(T entity)
    {
        _objectSet.UpdateModel(entity);
    }

    public abstract void Upsert(T entity);


}

具体的存储库如下所示:

public class UserAccountRepository : Repository<UserAccount>
{
    public UserAccountRepository(ObjectContext context)
        : base(context)
    {
    }

    public UserAccount GetById(int id)
    {
        return _objectSet.SingleOrDefault(user => user.ID == id);
    }

    public override void Upsert(UserAccount user)
    {
        if (user == null)
            throw new ArgumentNullException();
        if (user.ID == 0 || GetById(user.ID) == null)
            Add(user);
        else
            Update(user);
    }
}

接下来是 UnitOfWork 类。此类包含每个存储库的延迟加载实例,并实例化它自己的 ObjectContext,它在 UnitOfWork 的生命周期内保持事件状态。此上下文在其构造函数中传递给存储库。

UnitOfWork 类被实例化,更改通过可公开访问的存储库进行,然后通过 UnitOfWork 类的公共(public)方法保存或处置。

UnitOfWork 类:

(我只包含了 UserAccount、ComponentPermissions 和 Component。一个 UserAccount 可以访问多个具有不同级别权限的组件,这些权限在中间表 ComponentPermissions 中维护)

public class UnitOfWork : IDisposable
{


    #region Fields

    private readonly ObjectContext _context;

    private ComponentPermissionsRepository _componentPermissions;
    private ComponentRepository _components;
    private UserAccountRepository _userAccounts;

    #endregion //Fields


    #region Constructor

    public UnitOfWork()
    {
        _context = (new DataAccess.Entities() as IObjectContextAdapter).ObjectContext;
    }

    #endregion //Constructor


    #region Public Interface

    public ComponentPermissionsRepository ComponentPermissions
    {
        get
        {
            if (_componentPermissions == null)
            {
                _componentPermissions = new ComponentPermissionsRepository(_context);
            }

            return _componentPermissions;
        }

    }

    public ComponentRepository Components
    {
        get
        {
            if (_components == null)
            {
                _components = new ComponentRepository(_context);
            }

            return _components;
        }

    }


    public UserAccountRepository UserAccounts
    {
        get
        {
            if (_userAccounts == null)
            {
                _userAccounts = new UserAccountRepository(_context);
            }

            return _userAccounts;
        }

    }

    public void Commit()
    {
        _context.SaveChanges();
    }

    public void Dispose()
    {
        _userAccount = null;
        _component = null;
        _componentPermissions = null;
        _context.Dispose();
    }

    #endregion //Public Interface


}

我已经阅读了很多关于使用 EF 进行查询的文章,但是当应用于上述架构时,我所阅读的任何内容似乎都不起作用......而且我有一种可怕的感觉,我已经搬起石头砸自己的脚了,但我看不到位置。

在给定单个 UserAccount 的情况下,我想获得可访问组件的列表和相应的 ComponentPermissions。我怎样才能做这种查询? EF 导航属性似乎只适用于直接邻居......我是否遗漏了一些明显的东西?

编辑

有人指出我应该更具体地说明我的问题。我无法克服的第一个障碍是所有示例似乎都遵循:

context.Component.Include( c => c.ComponentPermissions.Select(cps => cps.UserAccount)).ToList();

看起来不错,但我没有公开我的上下文,即使我公开了,它也没有像 Component 这样的任何实体类型。但现在我已经将 GetAll() 更改为 IQueryable,我已经设法拼凑了以下内容:

List<Component> comps = uow.Components.GetAll().Include(c => c.UserPermissions.Select(cps => cps.UserAccount)).ToList();
ComponentPermissions compPer = comps[0].UserPermissions.Select(up => up).Where(up => up.UserAccount.UserName == userAccount).FirstOrDefault();

这会返回与给定 userAccount 相关的第一个 ComponentPermissions 对象...但这似乎是错误的,即使它有点工作(我说有点工作,因为它只有一个 ComponentPermissions 对象,不是所有的......但我不知道该怎么做)

那么,看看这个,有人能解释一下正确的方法吗?

最佳答案

好吧,我觉得自己有点像个白痴......

我通过以下方式获取 UnitOfWork 中的 ObjectContext:

_context = (new DataAccess.Entities() as IObjectContextAdapter).ObjectContext;

当我应该只使用 DataAccess.Entities() 的实例(EF 为我的数据创建的自定义上下文)时。

我不得不重做我的存储库,但一个额外的好处是我认为我现在可以摆脱我的具体类,而只使用通用存储库。

我遇到所有这些问题是因为我将 DataAccess.Entities() 转换为 ObjectContext,它不包含任何我的特定实体类型...所以我试图从仅加载数据的存储库中查询他们自己的类型。

一行代码……头疼三天。典型。

关于c# - 使用存储库和工作单元查询 EF 5.0,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13591348/

相关文章:

c# - 在不重新查询数据库的情况下,在另一个 LINQ 查询中重用 LINQ 查询结果

c# - 对实体执行 CRUD 操作的最佳实践( Entity Framework )

windows - 使用 Windows 推送 Gerrit

c# - 免费/开放图书馆以查找相似图像

c# - 如何防止 .NET 库在关闭时发送 RST 数据包

c# - MYSQL Huge记录并找到每个最近的点

c# - 如何使用数据库优先方法将 EF 6.2 中的现有数据项目加载到 Web API Core2 Controller 中?

java - Spring4中从Service访问Repository时出现NullPointerException

svn - 重命名SVN文件夹后如何将其拆分到自己的存储库中?

c# - 动态更改数组中的 MVVM INotifyPropertyChanged