简体   繁体   English

Linq to Entities with Repository Pattern 和 EF

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM