多租户架构下的实体框架 - 根据租户ID过滤单个表

7
我们正在寻找一种自动过滤Entity Framework中所有CRUD操作的租户ID的方法。
我们想到的方法有:
- 使用表值用户定义函数 - 使用存储过程(但我们不想这样做,因为我们使用ORM来避免使用存储过程) - 修改用于生成SQL的模板,以在每个语句中添加where子句。 - 修改用于生成控制器中LINQ的模板(我们可能会使用MVC)。
有什么建议吗?
谢谢, Alex。

1
现在在 EF Core 中可以使用全局查询过滤器实现这一点:https://learn.microsoft.com/en-us/ef/core/querying/filters - Fred
非常好的提示!我现在处于一个不同的世界,但是在构建那个系统时,这将会非常有用!对于这个问题的未来观众,我成功地使用了Ladislav答案所启发的仓储模式实现了该系统,但我现在会认真考虑全局查询过滤器方法...然而值得注意的是,我已经有几年没有做EF工作了。 - Alex KeySmith
2个回答

13
使用表值用户定义函数
表值函数仅在.NET 4.5 Beta中提供(不适用于Code First)。即使使用它们也没有帮助,因为您必须在每个LINQ查询中使用该函数,所以与使用where子句相同。
使用存储过程(但我们真的不想这样做,因为我们正在使用ORM来避免这样做)
对于某些特殊复杂查询可能有用,但通常不是您想要的。
以某种方式修改用于生成SQL的模板,在每个语句上添加where子句。
太过复杂,抽象层次完全不同。
以某种方式修改用于在控制器中生成LINQ的模板(我们可能使用MVC)。
接近理想的解决方案。您只需要将对实体集的访问包装在一些代码中,看起来像:
public class MultiTenantAccess<T> where T : IMultitenant
{
    private IDbSet<T> set;  

    ... 

    public IQueryable<T> GetQuery(int tenantID) 
    {
        return set.Where(e => e.TenantID == tenantID); 
    }
}

有时候这对于被称为通用仓储的东西来说是核心,但实际上它只是EF set的一个包装器。您将始终使用GetQuery来查询数据存储而不是直接使用DbSet


嗨@Ladislav,我无法想象IMultitenant应该包含什么,如果您有空的话,能否详细说明一下?谢谢 :-) - Alex KeySmith
其实我在想,IMultitenant 接口中应该包含 TenantId 吧?我的理解对吗? - Alex KeySmith
是的,它必须定义“TenantId”,并且您的实体必须实现该接口。 - Ladislav Mrnka
感谢 @Ladislav,我想我已经搞定了。我认为我需要阅读一些有关仓储模式的资料。再次感谢您的帮助。 - Alex KeySmith
嗨@Ladislav,再次感谢您的出色回答。我已经进行了一些测试实现,效果很好。但我想知道您是否有任何可能的替代方案。我们希望使用动态数据来生成一些后端管理页面,这与EntityDataSource最搭配。我一直在绞尽脑汁,但无法想到一种方法-是否有替代通用仓储库模式的方式来注入某种过滤器-也许是覆盖dbset?但我似乎无法做出任何事情。 - Alex KeySmith
@LadislavMrnka 你好,警告:使用EF的共享数据库的多租户存在安全隐患,请查看:https://dev59.com/YYvda4cB1Zd3GeqPeM2A - Rod

3

您可以将租户数据分别存储在不同的数据库中,或者存储在同一个数据库中但使用不同的模式?您可以在一篇旧的MSDN文章中了解更多关于这个的信息,该文章名为“Multi-Tenant Data Architecture”。


1
谢谢你的分享,Oakman。是的,我曾经看过这篇好文章。当时只有共享数据库和共享模式适合我们,但这是一个值得列在这个问题中的有价值的链接。我的投票+1。 - Alex KeySmith
这个链接已经失效了。你知道最新的URL吗? - aldo
我在[http://ramblingsofraju.com/wp-content/uploads/2016/08/Multi-Tenant-Data-Architecture.pdf]找到了一篇文章的PDF。 - oakman
PDF和MSDN链接已经失效。有最新的URL可以提供帮助吗? - SaiKiran Mandhala

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接