簡體   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