简体   繁体   English

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

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

I have a webservice which tries to connect to a database of a desktop accounting application.我有一个网络服务,它试图连接到桌面会计应用程序的数据库。

It have tables with same name but with different schema names such as:它具有名称相同但模式名称不同的表,例如:

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

Schema name is in format [Year+IncrementalNumber] such as [202014] , [202015] , [202016] and etc.架构名称采用[Year+IncrementalNumber]格式,例如[202014][202015][202016]等。

Whenever I want to query customer credit information in database, I should fetch information from schema with biggest number such as [DatabaseName].[202016].[CustomerCredit] if 202016 is latest schema in my db.每当我想在数据库中查询客户信用信息时,我应该从最大编号的模式中获取信息,例如[DatabaseName].[202016].[CustomerCredit]如果 202016 是我数据库中的最新模式。

Note: Creation of new schema in accounting application database have no rules and is completely decided by user of accounting application and every instance of application installed on different place may have different number of schemas.注意:会计应用数据库中新模式的创建没有规则,完全由会计应用的用户决定,安装在不同地方的每个应用实例可能有不同数量的模式。

So when I'm developing my webservice I have no idea to connect to which schema prior to development.所以当我开发我的网络服务时,我不知道在开发之前连接到哪个模式。 In run-time I can find correct schema to query from its tables but I don't know how to manage to fetch table information with correct schema name in query.在运行时,我可以找到正确的模式以从其表中查询,但我不知道如何在查询中使用正确的模式名称获取表信息。 I ususally creat a linq-to-sql dbml class and use its definitions to read information from db but I don't know how to manage schema change in this way?我通常创建一个 linq-to-sql dbml 类并使用其定义从 db 读取信息,但我不知道如何以这种方式管理架构更改?

DBML designer manage Scehma names like this: DBML 设计器像这样管理 Scehma 名称:

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

However since my app can retrieve schema name in run time, I don't know how to fix table declaration in my special case.但是,由于我的应用程序可以在运行时检索架构名称,因此我不知道如何在我的特殊情况下修复表声明。 It is so easy to handle in ADO.NET but I don't know its equivalent in Linq2SQL:在 ADO.NET 中很容易处理,但我不知道它在 Linq2SQL 中的等价物:

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

Ultimately, no: most ORMs do not expect the schema change to vary at runtime, so most - including EF and LINQ-to-SQL do not support this scenario.最终,不:大多数 ORM 不希望架构更改在运行时发生变化,因此大多数 - 包括 EF 和 LINQ-to-SQL 不支持这种情况。 One possible option would be to have different connection strings, each with different user accounts , that each has a different default schema configured at the database - and intialize your DB-context with a connection-string or connection that matches the required account.一种可能的选择是拥有不同的连接字符串,每个连接字符串都有不同的用户帐户,每个连接字符串在数据库中配置了不同的默认架构 - 并使用与所需帐户匹配的连接字符串或连接初始化您的数据库上下文。 Then if EF asks the RDBMS for [CustomerCredit] , it will look first in that account's schema ( [202014].[CustomerCredit] ).然后,如果 EF 向 RDBMS 询问[CustomerCredit] ,它将首先查看该帐户的架构 ( [202014].[CustomerCredit] )。 You should probably avoid having a [202014].[CustomerCredit] in that scenario, to prevent confusion.在这种情况下,您可能应该避免使用[202014].[CustomerCredit] ,以防止混淆。 This is, however, a pretty hacky and ugly solution.然而,这是一个非常笨拙和丑陋的解决方案。 But... it should work.但是......它应该工作。

Alternatively, you would have to take more control over the data access, essentially writing your own SQL (presumably with a token replacement for the schema, which has problems of its own).或者,您必须对数据访问进行更多控制,本质上是编写您自己的 SQL(大概是用令牌替换模式,它有其自身的问题)。

That schema is essentially a manual partitioning of the CustomerCredit table.该模式本质上是CustomerCredit表的手动分区。 The best solution would one that makes partitioning transparent to all users.最好的解决方案是使分区对所有用户透明。 The code shouldn't know how the data is partitioned.代码不应该知道数据是如何分区的。

Database Solutions数据库解决方案

The benefit of database solutions is that they are transparent or almost transparent to users and require minimal maintenance数据库解决方案的好处是它们对用户透明或几乎透明,并且需要最少的维护

Table Partitioning表分区

The clean solution would be to use table partitioning , making the different partitions transparent to all users.干净的解决方案是使用表分区,使不同的分区对所有用户透明。 Table partitioning used to be an Enterprise-only feature but it became available in all editions since SQL Server 2016 SP1, even Express.表分区曾经是一项仅限企业的功能,但它在 SQL Server 2016 SP1 之后的所有版本中都可用,甚至是 Express。 This means it's free in all versions still in mainstream support.这意味着它在仍受主流支持的所有版本中都是免费的。

The table is partitioned based on a function (eg a date based function) and stored in different files.该表基于函数(例如基于日期的函数)进行分区并存储在不同的文件中。 Whenever possible, the query optimizer can check the partition boundaries and the query conditions and use only the file that contains the relevant data.只要有可能,查询优化器就可以检查分区边界和查询条件,并且只使用包含相关数据的文件。 Eg in a date-partitioned table, queries that contain a date filter can search only the relevant partitions.例如,在日期分区表中,包含日期过滤器的查询只能搜索相关分区。

Partitioned views分区视图

Another option, available since 2000 at least, is to use partitionend views , essentially a UNION ALL view that combines all table partitions, eg :至少自 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 can map entities to views instead of tables. EF 可以将实体映射到视图而不是表。 If the criteria for updatable views are met, the partitioned view itself will be updatable and any modifications will be made to the correct table.如果满足可更新视图的标准,则分区视图本身将是可更新的,并且将对正确的表进行任何修改。

The query optimizer can take advantage of CHECK constraints on the tables to search only one table at a time, similar to how partitioned tables work.查询优化器可以利用表上的 CHECK 约束一次仅搜索一个表,类似于分区表的工作方式。

Code solutions代码解决方案

This requires raw SQL queries, and a way to identify the correct table/schema each time a change is made.这需要原始 SQL 查询,以及每次进行更改时识别正确表/模式的方法。 It requires modifications to the application each time the table partitioning changes, whether those are code modifications, or changes in a configuration file.每次表分区更改时,它都需要对应用程序进行修改,无论是代码修改还是配置文件中的更改。

In all cases, one query can only read from one table at a time在所有情况下,一个查询一次只能从一张表中读取

Keep ADO.NET保留 ADO.NET

One possibility is to keep using ADO.NET, replacing the table/schema name in a query template.一种可能性是继续使用 ADO.NET,替换查询模板中的表/模式名称。 The code will have to map to objects if needed, the same way it already did.如果需要,代码必须映射到对象,就像它已经做的那样。

EF Raw SQL EF 原始 SQL

Another, is to use EF's raw SQL features, eg EF Core's FromSqlRaw to query from a specific table , the same way ADO.NET would.另一个是使用 EF 的原始 SQL 功能,例如 EF Core 的FromSqlRaw从特定表中查询,与 ADO.NET 相同。 The benefit is that EF will map the query results to objects.好处是 EF 会将查询结果映射到对象。 In EF Core, the raw query can be combined with LINQ operators :在 EF Core 中,原始查询可以与 LINQ 运算符结合使用:

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

Dapper小巧玲珑

Another option is to use Dapper or another micro-ORM with an ad-hoc query, similar to ADO.NET, and map the results to objects:另一种选择是使用 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