我最近一直在研究实体框架和存储库模式,在存储库类中,我创建了一个名为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) {}
...
}
答案 0 :(得分:0)
你能试试吗
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");
}
}
答案 1 :(得分:0)
我强烈建议您使用简化的存储库模式,该模式将有助于模拟您的数据源以进行测试,并提供更大的灵活性。我不建议使用通用存储库,而是将存储库视为类似于Controller的存储库。 (我为一组特定的操作提供数据)尽管相对于DNRY更支持SRP,但减少了依赖性引用的数量。
例如:
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-ism“泄漏”到控制器中。但是,它泄漏它们的方法不过是传递表达式以试图提取EF的复杂方法而已。每个条件表达式同样容易需要遵循EF-ism。 (即,传递引用实体上的私有方法或静态方法的order-by表达式)
像这样的存储库模式(相对于仅让代码访问DbSet)的好处是易于测试。模拟的存储库只需要返回List<T>
AsQueryable
,您的控制器等可以单独进行测试。它还为所需的过滤器和针对实体的操作提供了很好的集中化。
答案 2 :(得分:0)
问题是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");