程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 4.4 異構、多數據庫的存取組件,4.4異構存取組件

4.4 異構、多數據庫的存取組件,4.4異構存取組件

編輯:關於.NET

4.4 異構、多數據庫的存取組件,4.4異構存取組件


在一個大型系統中,應該允許訪問多個數據庫,甚至是多個異構的數據庫。例如表單模塊使用mysql,數據倉庫模塊使用oracle等等。按照這個目標,數據的配置信息:

 

 1     "Database": {
 2       "ConnectionStrings": [
 3         {
 4           "Name": "MicroStrutLibrary",
 5           "ConnectionString": "Data Source=XXXX;Initial Catalog=XXXX;User Id=OperUser;Password=OperUser;MultipleActiveResultSets=true;Persist Security Info=true",
 6           "ProviderName": "System.Data.SqlClient"
 7         },
 8         {
 9           "Name": "CMS",
10           "ConnectionString": "Data Source=XXXX;Initial Catalog=XXXX;User Id=OperUser;Password=OperUser;MultipleActiveResultSets=true;Persist Security Info=true",
11           "ProviderName": "System.Data.SqlClient"
12         }
13       ],
14       "Providers": [
15         {
16           "Name": "System.Data.SqlClient",
17           "Type": "MicroStrutLibrary.Infrastructure.Core.Data.Entity.SqlServerDbContextOptionsBuilderProvider, MicroStrutLibrary.Infrastructure.Core.Data.Entity"
18         }
19       ]
20     }

 

每個數據庫都有一個Name(名稱,以後都用這個名稱訪問)、ConnectionString(數據庫鏈接串)、ProviderName(提供程序名)。對於ProviderName(提供程序名)在Providers中描述了對應的實現類描述TypeDescription。從上面我們可以看出,我們可以設置多個數據庫,不同的數據庫可以設置不同的Provider,也就是不同的數據庫類型,從而實現了多個異構數據庫的存取操作。

對於數據庫配置信息類DataConfigInfo,實現ConfigInfo,應該很簡單,就不贅述了,可以參見可換源的配置。

框架中,每個模塊(例如公共模塊、數據倉庫模塊、表單模塊、CMS模塊、授權認證模塊等)都對應於一個數據庫上下文DbContext。這個數據庫上下文指向一個數據庫,也就是要對應上數據配置中的Name屬性。我們的做法是新建一個DbNameAttribute,放在DbContext上,以確定具體數據庫的Name。

 

 1     /// <summary>
 2     /// 指定數據庫名稱特性
 3     /// </summary>
 4     [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
 5     public class DbNameAttribute : Attribute
 6     {
 7         /// <summary>
 8         /// 數據庫名稱
 9         /// </summary>
10         public string Name { get; set; }
11 
12         /// <summary>
13         /// 構造函數
14         /// </summary>
15         /// <param name="name"></param>
16         public DbNameAttribute(string name)
17         {
18             this.Name = name;
19         }
20 }

 

DBNameAttribute中的Name應該設置的就是配置中的Name,從而確保DbContext對應的是哪個數據庫。

例如公共模塊部分的DbContext寫法如下:

 1     [DbName("MicroStrutLibrary")]
 2     public class CommonDbContext : EntityDbContext
 3     {
 4         public CommonDbContext(DbContextOptions<CommonDbContext> options) : base(options)
 5         {
 6         }
 7 
 8         public DbSet<AccessoryInfo> Accessories { get; set; }
 9 
10         public DbSet<SystemParameterInfo> SystemParameters { get; set; }
11         public DbSet<SystemParameterDetailInfo> SystemParameterDetails { get; set; }
12     ……
13     }

大家會注意到CommonDbContext繼承EntityDbContext,他是框架的數據庫上下文抽象基類,繼承DbContext。這個抽象類的重寫OnModelCreating方法,找出當前具體實現EntityDbContext類(例如CommonDbContext)的所有DbSet屬性,形成該EntityDbContext用到的所有DbSet泛型的參數類,就是AccessoryInfo、SystemParameterInfo等類。然後找出所有繼承ORMapping關系映射基類EntityTypeConfiguration的子類,創建映射綁定關系。

抽象的關系映射基類EntityTypeConfiguration代碼如下:

 

1     public abstract class EntityTypeConfiguration<T> where T: class
2     {
3         public void Bind(ModelBuilder modelBuilder)
4         {
5             InnerBind(modelBuilder.Entity<T>());
6         }
7 
8         protected abstract void InnerBind(EntityTypeBuilder<T> builder);
9     }

 

例如系統參數的ORMapping類就可以寫成:

 

 1     /// <summary>
 2     /// 系統參數 映射信息
 3     /// </summary>
 4     public class SystemParameterMapper : EntityTypeConfiguration<SystemParameterInfo>
 5     {
 6         protected override void InnerBind(EntityTypeBuilder<SystemParameterInfo> builder)
 7         {
 8             builder.ToTable("SYSTEM_PARAMETER_INFO");
 9 
10             builder.Property(p => p.AppCode).HasColumnName("APP_CODE").IsRequired();
11             builder.Property(p => p.SystemParaCode).HasColumnName("SYSTEM_PARA_CODE").IsRequired();
12             builder.Property(p => p.SystemParaName).HasColumnName("SYSTEM_PARA_NAME").IsRequired();
13             builder.Property(p => p.SortOrder).HasColumnName("SORT_ORDER").IsRequired();
14             builder.Property(p => p.Remark).HasColumnName("REMARK");
15 
16             builder.HasKey(p => new { p.AppCode, p.SystemParaCode });
17 
18             builder.HasMany(p => p.DetailList).WithOne().HasForeignKey(f => new { f.AppCode, f.SystemParaCode }).OnDelete(DeleteBehavior.Cascade);
19         }
20     }

 

前面講了數據庫的配置說明,DbContext的具體實現和ORMapping的實現。但是在程序中如何嵌入這些內容,如何將DbContext與配置關聯呢?尤其是數據庫的Provider是寫在配置中的,不能再在Startup中寫死services.AddDbContext<BloggingContext>(options => options.UseSqlServer(connection))吧?這種寫法,背離了我們使用配置方式的初衷了。

為了解決這個問題,我們寫一個startup的擴展方法,將配置和DbContext等關聯起來:

 

 1         public static DbContextOptionsBuilder UseDb<TContext>(this DbContextOptionsBuilder optionsBuilder, IServiceProvider serviceProvider) where TContext : DbContext
 2         {
 3             DataConfigInfo config = serviceProvider.GetService<IOptions<DataConfigInfo>>().Value;
 4 
 5             DbNameAttribute attribute = typeof(TContext).GetTypeInfo().GetCustomAttribute<DbNameAttribute>(false);
 6 
 7             ConnectionStringSettingInfo connectionStringSetting = config.ConnectionStrings.SingleOrDefault(o => o.Name == attribute.Name);
 8             ProviderSettingInfo providerSetting = config.Providers.SingleOrDefault(o => o.Name == connectionStringSetting.ProviderName);
 9 
10             Type providerType = Type.GetType(providerSetting.Type);
11 
12             DbContextOptionsBuilderProvider providerInstance = Activator.CreateInstance(providerType) as DbContextOptionsBuilderProvider;
13 
14             providerInstance.ConnectionStringSetting = connectionStringSetting;
15             providerInstance.ProviderSetting = providerSetting;
16 
17             providerInstance.Build(optionsBuilder);
18 
19             EntityDbContext.DbContexts.TryAdd(connectionStringSetting.Name, typeof(TContext));
20 
21             return optionsBuilder;
22         }

 

這個方法的主要作用是:TContext泛型參數是EntityDbContext的實現類,例如CommonDbContext。以上面介紹的數據庫配置信息和CommonDbContext為例說明:

1、獲取當前CommonDbContext類的DbNameAttribute,也就是MicroStrutLibrary。

2、然後獲取MicroStrutLibrary數據庫連接串信息

"Name": "MicroStrutLibrary",

"ConnectionString": "Data Source=XXXX;Initial Catalog=XXXX;User Id=OperUser;Password=OperUser;MultipleActiveResultSets=true;Persist Security Info=true",

"ProviderName": "System.Data.SqlClient"

3、再找出對應的DbProvider信息

"Name": "System.Data.SqlClient",

"Type": "MicroStrutLibrary.Infrastructure.Core.Data.Entity.SqlServerDbContextOptionsBuilderProvider, MicroStrutLibrary.Infrastructure.Core.Data.Entity"

4、根據DbProvider信息創建DbContextOptionsBuilderProvider類的實例,並設置屬性,執行實例的Build方法。具體這個類在下面講解。

5、將當前TContext追加到EntityDbContext基類的靜態屬性DbContexts字典中。這個字典主要是存放數據庫的Name和TContext的對應關系。目前暫且用不到(在通用數據查詢功能中用的,以後會介紹)。

 

重點來了,DbContextOptionsBuilderProvider類就是針對每種類型數據庫SQL Server、MySql、Oracle等的提供程序。Build方法的參數是各種數據庫類型的OptionsBuilder,這個OptionsBuilder在.net core類庫中,只需要在他們的基礎上封裝一下即可:

 

 1     public abstract class DbContextOptionsBuilderProvider
 2     {
 3         public ProviderSettingInfo ProviderSetting { get; set; }
 4 
 5         public ConnectionStringSettingInfo ConnectionStringSetting { get; set; }
 6 
 7         public abstract void Build(DbContextOptionsBuilder optionsBuilder);
 8    }
 9 
10     public class SqlServerDbContextOptionsBuilderProvider : DbContextOptionsBuilderProvider
11     {
12         public override void Build(DbContextOptionsBuilder optionsBuilder)
13         {
14             //SQLServer 2008 R2以以下版本
15             optionsBuilder.UseSqlServer(this.ConnectionStringSetting.ConnectionString, ob => ob.UseRowNumberForPaging());
16             //SQLSever 2012以上版本
17             //optionsBuilder.UseSqlServer(this.ConnectionStringSetting.ConnectionString);
18         }
19    }

 

 

上面就是一個SQLServer的具體實現,不過有個說明的是SQLServer 2008R2及以下版本沒有offset fetch next語句,只能使用row_number() over方式,因此當數據庫是SQLServer 2008R2及以下版本使用optionsBuilder.UseSqlServer(this.ConnectionStringSetting.ConnectionString, ob => ob.UseRowNumberForPaging()),而SQLServer 2012以上版本使用optionsBuilder.UseSqlServer(this.ConnectionStringSetting.ConnectionString)。

還有一點說明的是SQLServer數據庫使用datetime2,而不是datetime,否則轉換會報錯。

 

面向雲的.net core開發框架目錄

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved