c# – EF Core 2.0.0查询过滤器正在缓存TenantId(针对2.0.1进行了更新)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了c# – EF Core 2.0.0查询过滤器正在缓存TenantId(针对2.0.1进行了更新),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4400字,纯文字阅读大概需要7分钟。
内容图文
![c# – EF Core 2.0.0查询过滤器正在缓存TenantId(针对2.0.1进行了更新)](/upload/InfoBanner/zyjiaocheng/806/aba57ba5183d433e944463cc068d743c.jpg)
我正在构建一个多租户应用程序,并且遇到了我认为EF Core在请求中缓存租户ID的困难.唯一似乎有帮助的是在我登录和退出租户时不断重建应用程序.
我认为它可能与IHttpContextAccessor实例是单例有关,但它不能作为范围,当我在没有重建的情况下登录和退出时,我可以看到租户的名称在页面顶部发生变化,所以它不是问题.
我能想到的另一件事是EF Core正在进行某种查询缓存.我不确定为什么它会考虑它是一个范围的实例,它应该在每个请求上重建,除非我错了,我可能是.我希望它的行为类似于作用域实例,因此我可以在模型构建时在每个实例上简单地注入租户ID.
如果有人能指出我正确的方向,我真的很感激.这是我目前的代码:
TenantProvider.cs
public sealed class TenantProvider :
ITenantProvider {
private readonly IHttpContextAccessor _accessor;
public TenantProvider(
IHttpContextAccessor accessor) {
_accessor = accessor;
}
public int GetId() {
return _accessor.HttpContext.User.GetTenantId();
}
}
…注入TenantEntityConfigurationBase.cs,我用它来设置全局查询过滤器.
internal abstract class TenantEntityConfigurationBase<TEntity, TKey> :
EntityConfigurationBase<TEntity, TKey>
where TEntity : TenantEntityBase<TKey>
where TKey : IEquatable<TKey> {
protected readonly ITenantProvider TenantProvider;
protected TenantEntityConfigurationBase(
string table,
string schema,
ITenantProvider tenantProvider) :
base(table, schema) {
TenantProvider = tenantProvider;
}
protected override void ConfigureFilters(
EntityTypeBuilder<TEntity> builder) {
base.ConfigureFilters(builder);
builder.HasQueryFilter(
e => e.TenantId == TenantProvider.GetId());
}
protected override void ConfigureRelationships(
EntityTypeBuilder<TEntity> builder) {
base.ConfigureRelationships(builder);
builder.HasOne(
t => t.Tenant).WithMany().HasForeignKey(
k => k.TenantId);
}
}
…然后由所有其他租户实体配置继承.不幸的是,它似乎没有按照我的计划运作.
我已经验证了用户主体返回的租户ID正在根据租户用户的登录情况而变化,因此这不是问题.在此先感谢您的帮助!
更新
有关使用EF Core 2.0.1的解决方案,请查看我未接受的答案.
更新2
另请参阅Ivan的2.0.1更新,它代理DbContext的过滤器表达式,它恢复了在基本配置类中定义一次的能力.这两种解决方案各有利弊.我再次选择了Ivan,因为我只想尽可能地利用我的基本配置.
解决方法:
目前(从EF Core 2.0.0开始),动态全局查询过滤非常有限.仅当动态部分由目标DbContext派生类(或其基本DbContext派生类之一)的直接属性提供时,它才有效.正如文档中的Model-level query filters示例一样.正是这样 – 没有方法调用,没有嵌套属性访问器 – 只是上下文的属性.有点在链接中解释:
Note the use of a
DbContext
instance level property:TenantId
. Model-level filters will use the value from the correct context instance. i.e. the one that is executing the query.
要使它在您的场景中工作,您必须创建一个这样的基类:
public abstract class TenantDbContext : DbContext
{
protected ITenantProvider TenantProvider;
internal int TenantId => TenantProvider.GetId();
}
从它派生你的上下文类,并以某种方式将TenantProvider实例注入其中.然后修改TenantEntityConfigurationBase类以接收TenantDbContext:
internal abstract class TenantEntityConfigurationBase<TEntity, TKey> :
EntityConfigurationBase<TEntity, TKey>
where TEntity : TenantEntityBase<TKey>
where TKey : IEquatable<TKey> {
protected readonly TenantDbContext Context;
protected TenantEntityConfigurationBase(
string table,
string schema,
TenantDbContext context) :
base(table, schema) {
Context = context;
}
protected override void ConfigureFilters(
EntityTypeBuilder<TEntity> builder) {
base.ConfigureFilters(builder);
builder.HasQueryFilter(
e => e.TenantId == Context.TenantId);
}
protected override void ConfigureRelationships(
EntityTypeBuilder<TEntity> builder) {
base.ConfigureRelationships(builder);
builder.HasOne(
t => t.Tenant).WithMany().HasForeignKey(
k => k.TenantId);
}
}
一切都会按预期工作.请记住,Context变量类型必须是DbContext派生类 – 用接口替换它将不起作用.
2.0.1的更新:正如@Smit在评论中指出的那样,v2.0.1删除了大部分限制 – 现在你可以使用方法和子属性了.
但是,它引入了另一个要求 – 动态表达式必须以DbContext为根.
这个要求打破了上述解决方案,因为表达式root是TenantEntityConfigurationBase< TEntity,TKey>因为缺少编译时间支持来生成常量表达式,所以在DbContext之外创建这样的表达式并不容易.
它可以通过一些低级表达式操作方法来解决,但在您的情况下,更容易在TenantDbContext的通用实例方法中移动过滤器创建,并从实体配置类调用它.
以下是修改:
TenantDbContext类:
internal Expression<Func<TEntity, bool>> CreateFilter<TEntity, TKey>()
where TEntity : TenantEntityBase<TKey>
where TKey : IEquatable<TKey>
{
return e => e.TenantId == TenantId;
}
TenantEntityConfigurationBase< TEntity,TKey>类:
builder.HasQueryFilter(Context.CreateFilter<TEntity, TKey>());
内容总结
以上是互联网集市为您收集整理的c# – EF Core 2.0.0查询过滤器正在缓存TenantId(针对2.0.1进行了更新)全部内容,希望文章能够帮你解决c# – EF Core 2.0.0查询过滤器正在缓存TenantId(针对2.0.1进行了更新)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。