[英]Linq to Entities with Repository Pattern and EF
I have been recently working on a Entity Framework and Repository pattern, in the repository class i have created a function called find, which takes a predicate generates the entity out of it.我最近一直在研究实体框架和存储库模式,在存储库类中我创建了一个名为 find 的函数,它使用一个谓词从中生成实体。 here's my Repository function.
这是我的存储库功能。
public T Find(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).First();
}
else
{
return query.First();
}
}
Here's my DTO class.这是我的 DTO 课程。
public class UsersDo
{
public int UserId {get;set}
public string Username {get;set}
...
}
Now i am calling the Find function on my page like:现在我在我的页面上调用 Find 函数,例如:
usersDao.Find(x=>x.Username == "username")
However i gets the error但是我得到了错误
The entity or complex type 'UsersDo' cannot be constructed in a LINQ to Entities query.
Could anyone suggest what's going wrong here.任何人都可以建议这里出了什么问题。
EDIT编辑
under repository class, i have a constructor:在存储库类下,我有一个构造函数:
private readonly DbSet<T> dbSet;
private readonly DataContext context;
public GenericDao(DataContext _context)
{
context = _context;
dbSet = context.Set<T>();
}
my Dao class:我的道课:
public class UsersDao : GenericDao<UsersDo>, IUsers
{
public UsersDao(DataContext context) : base (context) {}
...
}
Can you try this你能试试这个吗
public class UserContext : DbContext
{
public DbSet<UsersDo> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<UsersDo>()
.HasKey(e => e.UsersId);
base.OnModelCreating(modelBuilder);
}
}
public class Repo<T> where T : class
{
private readonly DbSet<T> dbSet;
public Repo(DbContext context)
{
dbSet = context.Set<T>();
}
public T Find(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)
{
query = orderby(query);
}
// If you use the First() method you will get an exception when the result is empty.
return query?.FirstOrDefault();
}
}
------- Test the code ------- 测试代码
internal class Program
{
private static void Main(string[] args)
{
var usersDao = new Repo<UsersDo>(new UserContext());
var r = usersDao.Find(x => x.Username == "username");
}
}
I'd highly recommend a simplified repository pattern that will help with mocking your data source for testing, and provide more flexibility.我强烈推荐一种简化的存储库模式,它有助于模拟您的数据源进行测试,并提供更大的灵活性。 I do not recommend using generic repositories, but rather to treat a repository similar to a Controller.
我不建议使用通用存储库,而是将存储库视为类似于控制器。 (I serve data for a particular set of operations) This cuts down on the number of dependency references, though favours SRP over DNRY.
(我为一组特定的操作提供数据)这减少了依赖项引用的数量,尽管有利于 SRP 而非 DNRY。
For example:例如:
public class OrderRepository : IOrderRepository
{
private MyDbContext Context
{
return _contextLocator.Get<MyDbContext>() ?? throw new InvalidOperation("The repository must be called from within a context scope.");
}
IQueryable<Order> IOrderRepository.GetOrders()
{
var query = Context.Orders.Where(x => x.IsActive);
return query;
}
IQueryable<Order> IOrderRepository.GetOrderById(int orderId)
{
var query = Context.Orders.Where(x => x.IsActive && x.OrderId == orderId);
return query;
}
Order IOrderRepository.CreateOrder( /* Required references/values */)
{
}
void IOrderRepository.DeleteOrder(Order order)
{
}
}
By returning IQueryable the consuming code can maintain control over optional filter criteria, sorting, paging, and operations against the data without triggering unnecessary data reads.通过返回 IQueryable,消费代码可以保持对可选过滤条件、排序、分页和数据操作的控制,而不会触发不必要的数据读取。 There is no need for complicated expression parameters for filtering, sorting, or extra parameters to manage paging.
不需要复杂的表达式参数来过滤、排序或管理分页的额外参数。 The repository serves as the gate-keeper for required filters such as IsActive, authorization checks, etc. The repository also can serve as an entity factory, ensuring that all mandatory fields and references are provided when creating a new entity.
存储库充当所需过滤器(例如 IsActive、授权检查等)的看门人。存储库还可以充当实体工厂,确保在创建新实体时提供所有必填字段和引用。 I also let the repository manage the delete operations to ensure that all validation and integrity are enforced, plus auditing records, and handle soft-delete scenarios.
我还让存储库管理删除操作,以确保执行所有验证和完整性,以及审计记录,并处理软删除场景。 (IsActive)
(活跃)
Some people shun the use of IQueryable on the grounds it "leaks" EF-isms into the controllers.有些人避免使用 IQueryable,理由是它会将 EF-isms“泄漏”到控制器中。 However, it leaks them no more than complicated methods passing expressions in an attempt to abstract away EF.
然而,它泄露的只是复杂的方法传递表达式以试图抽象出 EF。 Every condition expression is equally vulnerable to needing to conform with EF-isms.
每个条件表达式都同样容易受到需要符合 EF 主义的影响。 (Ie passing an order-by expression which references a private method on an entity or a static method)
(即传递一个 order-by 表达式,该表达式引用实体或静态方法上的私有方法)
The benefit of a repository pattern like this (versus just leaving code accessing DbSets) is ease of testing.像这样的存储库模式(而不是让代码访问 DbSet)的好处是易于测试。 A mocked repository just has to return a
List<T>
AsQueryable
and your controllers etc. can be tested in isolation. AsQueryable
存储库只需要返回一个List<T>
AsQueryable
并且您的控制器等可以单独测试。 It also provides a nice centralization for required filters and operations against entities.它还为所需的过滤器和实体操作提供了很好的集中化。
The problem is userDoa is not registered entity in your DbContext.问题是 userDoa 未在您的 DbContext 中注册实体。
Also,还,
public class UsersDao : GenericDao<UsersDo>, IUsers
{
public UsersDao(DataContext context) : base (context) {}
...
}
is not needed I believe.我相信不需要。 The problem is not related with your generic repository.
该问题与您的通用存储库无关。
public class DataContext : DbContext
{
public virtual DbSet<UserDo> UserDos { get; set; }
}
public class UserDo
{
[Key]
public int UserId {get;set}
public string Username {get;set}
}
then然后
var result = new UserContext().Find(x => x.Username == "John");
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.