繁体   English   中英

linq2sql C#:如何从更改架构名称的表中进行查询

[英]linq2sql C#: How to query from a table with changing schema name

我有一个网络服务,它试图连接到桌面会计应用程序的数据库。

它具有名称相同但模式名称不同的表,例如:

[DatabaseName].[202001].[CustomerCredit]
[DatabaseName].[202002].[CustomerCredit]
.
.
.
[DatabaseName].[202014].[CustomerCredit]
[DatabaseName].[202015].[CustomerCredit]
[DatabaseName].[202016].[CustomerCredit]
...
..
[DatabaseName].[2020xx].[CustomerCredit]

架构名称采用[Year+IncrementalNumber]格式,例如[202014][202015][202016]等。

每当我想在数据库中查询客户信用信息时,我应该从最大编号的模式中获取信息,例如[DatabaseName].[202016].[CustomerCredit]如果 202016 是我数据库中的最新模式。

注意:会计应用数据库中新模式的创建没有规则,完全由会计应用的用户决定,安装在不同地方的每个应用实例可能有不同数量的模式。

所以当我开发我的网络服务时,我不知道在开发之前连接到哪个模式。 在运行时,我可以找到正确的模式以从其表中查询,但我不知道如何在查询中使用正确的模式名称获取表信息。 我通常创建一个 linq-to-sql dbml 类并使用其定义从 db 读取信息,但我不知道如何以这种方式管理架构更改?

DBML 设计器像这样管理 Scehma 名称:

[global::System.Data.Linq.Mapping.TableAttribute(Name="[202001].CustomerCredit")]

但是,由于我的应用程序可以在运行时检索架构名称,因此我不知道如何在我的特殊情况下修复表声明。 在 ADO.NET 中很容易处理,但我不知道它在 Linq2SQL 中的等价物:

select count(*)  from [" + Variables.FinancialYearSchemaName + "].CustomerCredit  where SFC_Status = 100;

最终,不:大多数 ORM 不希望架构更改在运行时发生变化,因此大多数 - 包括 EF 和 LINQ-to-SQL 不支持这种情况。 一种可能的选择是拥有不同的连接字符串,每个连接字符串都有不同的用户帐户,每个连接字符串在数据库中配置了不同的默认架构 - 并使用与所需帐户匹配的连接字符串或连接初始化您的数据库上下文。 然后,如果 EF 向 RDBMS 询问[CustomerCredit] ,它将首先查看该帐户的架构 ( [202014].[CustomerCredit] )。 在这种情况下,您可能应该避免使用[202014].[CustomerCredit] ,以防止混淆。 然而,这是一个非常笨拙和丑陋的解决方案。 但是......它应该工作。

或者,您必须对数据访问进行更多控制,本质上是编写您自己的 SQL(大概是用令牌替换模式,它有其自身的问题)。

该模式本质上是CustomerCredit表的手动分区。 最好的解决方案是使分区对所有用户透明。 代码不应该知道数据是如何分区的。

数据库解决方案

数据库解决方案的好处是它们对用户透明或几乎透明,并且需要最少的维护

表分区

干净的解决方案是使用表分区,使不同的分区对所有用户透明。 表分区曾经是一项仅限企业的功能,但它在 SQL Server 2016 SP1 之后的所有版本中都可用,甚至是 Express。 这意味着它在仍受主流支持的所有版本中都是免费的。

该表基于函数(例如基于日期的函数)进行分区并存储在不同的文件中。 只要有可能,查询优化器就可以检查分区边界和查询条件,并且只使用包含相关数据的文件。 例如,在日期分区表中,包含日期过滤器的查询只能搜索相关分区。

分区视图

至少自 2000 年以来可用的另一个选项是使用partitionend 视图,本质上是一个结合所有表分区的UNION ALL视图,例如:

SELECT <select_list1>  
FROM [202001].[CustomerCredit]
UNION ALL  
SELECT <select_list2>  
FROM [202002].[CustomerCredit]
UNION ALL  
...  
SELECT <select_listn>  
FROM Tn;

EF 可以将实体映射到视图而不是表。 如果满足可更新视图的标准,则分区视图本身将是可更新的,并且将对正确的表进行任何修改。

查询优化器可以利用表上的 CHECK 约束一次仅搜索一个表,类似于分区表的工作方式。

代码解决方案

这需要原始 SQL 查询,以及每次进行更改时识别正确表/模式的方法。 每次表分区更改时,它都需要对应用程序进行修改,无论是代码修改还是配置文件中的更改。

在所有情况下,一个查询一次只能从一张表中读取

保留 ADO.NET

一种可能性是继续使用 ADO.NET,替换查询模板中的表/模式名称。 如果需要,代码必须映射到对象,就像它已经做的那样。

EF 原始 SQL

另一个是使用 EF 的原始 SQL 功能,例如 EF Core 的FromSqlRaw从特定表中查询,与 ADO.NET 相同。 好处是 EF 会将查询结果映射到对象。 在 EF Core 中,原始查询可以与 LINQ 运算符结合使用:

var query=$"select * from [DatabaseName].[{schemaName}].[CustomerCredit]"
var credits = context.CustomerCredits
    .FromSqlRaw(query)
    .Where(...)
    .ToList();

小巧玲珑

另一种选择是使用 Dapper 或其他具有临时查询的微 ORM,类似于 ADO.NET,并将结果映射到对象:

var query=$"select * from [DatabaseName].[{schemaName}].[CustomerCredit] where customerID=@ID";
var credits=connection.Query<CustomerCredit>(query,new {ID=someID});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM