6

我正在关注MSDN 上的这篇文章。我将它移植到 EF Code First。

public interface IUnitOfWork
{
    IRepository<Employee> Employees { get; }
    IRepository<TimeCard> TimeCards { get; }
    void Commit();
}

public class HrContext : DbContext
{
    public DbSet<Employee> Employees { get; set; }
    public DbSet<TimeCard> TimeCards { get; set; }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Employee>()
                    .HasMany(e => e.TimeCards)
                    .WithOptional(tc => tc.Employee);
     }
}

public class SqlRepository<T> : IRepository<T>
    where T : class
{
    private readonly DbSet<T> entitySet;
    public SqlRepository(DbContext context)
    {
        this.entitySet = context.Set<T>();
    }
    public void Add(T newEntity)
    {
        this.entitySet.Add(newEntity);
    }
    public IQueryable<T> FindAll()
    {
        return this.entitySet;
    }
    public T FindById(params object[] keys)
    {
        return this.entitySet.Find(keys);
    }
    public IQueryable<T> FindWhere(Expression<Func<T, bool>> predicate)
    {
        return this.entitySet.Where(predicate);
    }
    public void Remove(T entity)
    {
        this.entitySet.Remove(entity);
    }
}

public class SqlUnitOfWork : IUnitOfWork, IDisposable
{
    private readonly HrContext context;
    private IRepository<Employee> employees;
    private IRepository<TimeCard> timeCards;
    public SqlUnitOfWork()
    {
        this.context = new HrContext();
    }
    public IRepository<Employee> Employees
    {
        get
        {
            return new SqlRepository<Employee>(context);
        }
    }
    public IRepository<TimeCard> TimeCards
    {
        get
        {
            return new SqlRepository<TimeCard>(context);
        }
    }
    public void Commit()
    {
        this.context.SaveChanges();
    }
    public void Dispose()
    {
        context.Dispose();
    }
}

var query = from e in unitOfWork.Employees.FindAll()
            from tc in unitOfWork.TimeCards.FindAll()
            where tc.Employee.Id == e.Id && e.Name.StartsWith("C")
            select tc;
var timeCards = query.ToList();

这个模型很棒,因为它给了我可测试性。但是,像上面这样运行查询会抛出这个

LINQ to Entities does not recognize the method
 'System.Linq.IQueryable`1[DomainModel.Models.TimeCard] FindAll()' 
  method, and this method cannot be translated into a store expression.

我理解这个错误,但有什么方法可以避免它,但仍然保留存储库以进行可测试性?

4

1 回答 1

5

由于查询提供程序的工作方式和工作方式的性质,您的 select 语句无法翻译IQueryable<T>:有关更多信息,请参阅此线程IQueryable<T> 和 IEnumerable<T> 之间有什么区别?

您可以通过将表达式分成单独的语句来“帮助” linq 提供程序,如下所示:

var ems = unitOfWork.Employees.FindAll();
var tcs = unitOfWork.TimeCards.FindAll();

var query = from e in ems
            from tc in tcs
            where tc.Employee.Id == e.Id && e.Name.StartsWith("C")
            select tc;

或者您可以让 FindAll() 返回IEnumerable<T>而不是IQueryable<T>然后您的原始表达式应该可以工作。

于 2011-01-22T21:14:36.213 回答