为了账号安全,请及时绑定邮箱和手机立即绑定

Linq to Entity with Repository Pattern 和 EF

Linq to Entity with Repository Pattern 和 EF

C#
梦里花落0921 2022-07-10 15:58:29
我最近一直在研究实体框架和存储库模式,在存储库类中,我创建了一个名为 find 的函数,它使用谓词从中生成实体。这是我的存储库功能。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();    }}这是我的 DTO 课程。public class UsersDo{    public int UserId {get;set}    public string Username {get;set}    ...}现在我在我的页面上调用 Find 函数,例如:usersDao.Find(x=>x.Username == "username")但是我得到了错误The entity or complex type 'UsersDo' cannot be constructed in a LINQ to Entities query.谁能建议这里出了什么问题。在存储库类下编辑,我有一个构造函数:private readonly DbSet<T> dbSet;private readonly DataContext context;public GenericDao(DataContext _context){    context = _context;    dbSet = context.Set<T>();}我的道课:public class UsersDao : GenericDao<UsersDo>, IUsers{     public UsersDao(DataContext context) : base (context) {}     ...}
查看完整描述

3 回答

?
大话西游666

TA贡献1817条经验 获得超14个赞

问题是 userDoa 未在您的 DbContext 中注册实体。


还,


public class UsersDao : GenericDao<UsersDo>, IUsers

{

     public UsersDao(DataContext context) : base (context) {}

     ...

}

我相信不需要。该问题与您的通用存储库无关。


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}

}

然后


var result = new UserContext().Find(x => x.Username == "John");


查看完整回答
反对 回复 2022-07-10
?
茅侃侃

TA贡献1842条经验 获得超21个赞

你能试试这个


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();

    }

}

-------- 测试代码


internal class Program

{

    private static void Main(string[] args)

    {

        var usersDao = new Repo<UsersDo>(new UserContext());


        var r = usersDao.Find(x => x.Username == "username");

    }

}


查看完整回答
反对 回复 2022-07-10
?
catspeake

TA贡献1111条经验 获得超0个赞

我强烈推荐一种简化的存储库模式,这将有助于模拟您的数据源以进行测试,并提供更大的灵活性。我不建议使用通用存储库,而是将存储库类似于控制器。(我为一组特定的操作提供数据)这减少了依赖引用的数量,尽管有利于 SRP 而不是 DNRY。


例如:


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)

    {

    }

}

通过返回 IQueryable,消费代码可以保持对可选过滤条件、排序、分页和对数据的操作的控制,而不会触发不必要的数据读取。不需要用于过滤、排序的复杂表达式参数或用于管理分页的额外参数。存储库充当 IsActive、授权检查等所需过滤器的看门人。存储库还可以充当实体工厂,确保在创建新实体时提供所有必填字段和引用。我还让存储库管理删除操作,以确保强制执行所有验证和完整性,以及审计记录,并处理软删除场景。(活跃)


有些人回避使用 IQueryable,因为它会将 EF 主义“泄漏”到控制器中。然而,它泄露它们只不过是传递表达式以试图抽象出 EF 的复杂方法。每个条件表达式都同样容易需要符合 EF-isms。(即传递引用实体上的私有方法或静态方法的 order-by 表达式)


像这样的存储库模式(相对于只让代码访问 DbSet)的好处是易于测试。模拟存储库只需要返回 aList<T> AsQueryable并且您的控制器等可以单独测试。它还为所需的过滤器和针对实体的操作提供了很好的集中化。


查看完整回答
反对 回复 2022-07-10
  • 3 回答
  • 0 关注
  • 85 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信