我正在开发一个使用Entity Framework的应用程序,但是我遇到了一些性能问题.想象一下具有一些组合框和数据网格的用户界面(C#,WPF).每次在组合框中选择一个值时,它都会更改数据在网格中显示的条件.看起来实体框架在缓存方面没有我想象的那么灵活.由于条件已更改,底层sql将始终不同(=无EF缓存),每个单元更新将导致对数据库的请求.
有没有什么方法可以在本地缓存表(使用工作导航属性)并仍然使用linq进行选择等而不生成对数据库的任何请求?
这些表很小,所以我不希望出现任何性能问题.(我猜本地排序等可能是一个问题,因为没有使用数据库索引.)
我不需要对表的写访问权,所以如果有一种简单的方法来制作表的深层副本并从数据库连接中分离,那可能就行了.
我不允许安装任何第三方工具.
也许实体框架从一开始就是一个糟糕的选择,但是使用那些生成的类和linq而不是手动编写很多类和sql真的很方便.(我仍然需要实现一些缓存.)
有什么方法可以在本地缓存表吗?
这是DbContext
默认操作,您可以轻松使用该功能.以下是要遵循的基本模式:
context.Products.Where(p =>).Load(); var dataSource = context.Product.Local.Where(p => );
请注意,在第2行Local
中使用了集合.这是一个DbSet
从上下文缓存中返回实体的属性.
具有工作导航属性
由Load()
语句加载的任何相关实体将通过关系修正自动相互连接.因此,如果a Product
有一个集合Components
,你可以这样做:
context.Components.Where(c =>).Load();
如果这会加载上面加载的产品的所有组件,您将看到他们的Components
集合现在已填充.
结合这两个步骤的替代方案是:
context.Products.Where(p =>) .Include(p => p.Components) .Load();
如果有许多相关表,则必须在各个Load
语句和Load
语句之间找到平衡Include
,因为Includes
在一个语句中有许多可能会达到性能.
并仍然使用linq进行选择
如上图所示:灵活的条件.
不产生任何数据库请求
如果您始终Local
只处理集合,则这些语句将永远不会查询数据库.但是,寻址导航属性仍可能导致延迟加载.如果你这样做......
context.Products.Where().Load(); context.Components.Where().Load();
...这会填充product.Components
集合,但不会将它们标记为已加载,而是context.Products.Include(p => p.Components)
.因此,在第一种情况下,寻址product.Components
将触发延迟加载.类似地,解决根本未加载实体的导航属性也将触发延迟加载.因此,要确保不会触发任何数据库交互,您应该通过以下方式禁用延迟加载:
context.Configuration.LazyLoadingEnabled = false;
... 要么 ...
context.Configuration.ProxyCreationEnabled = false;
后一个选项强制EF创建不能延迟加载的简单POCO对象.
因此,使用这些技术,您可以将上下文用作连接实体的本地缓存.对于上下文应该是短暂的规则,这是一个例外.
一个警告
关系修正不适用于多对多关联.假设和m:n
之间存在关系,那么......Product
Manufacturer
context.Products.Where().Load(); context.Manufacturers.Where().Load();
...不会填充product.Manufacturers
和manufacturer.Products
.应该通过以下方式加载多对多关联Include
:
context.Products.Where() .Include(p => p.Manufacturers) .Load();