Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

多个IFreesql中进行区别的Aop配置在查询时出现的表名异常 #1542

Closed
mHalo opened this issue Jun 20, 2023 · 2 comments
Closed

Comments

@mHalo
Copy link

mHalo commented Jun 20, 2023

问题描述及重现代码:

针对dev/test/prod三个不同的环境,创建了对应的freesql实例存在缓存中,后续查询时会找到指定环境的freesql实例进行查询,
针对不同的实例,创建时通过AOP修改了对应表名,以达到针对不同的env使用指定schema下table的目的;
实际执行查询时发现生成的查询语句始终使用的是最后一次创建的freesql中aop所设置的表名; 如:

创建dev环境的freesql实例后,查询语句为:
SELECT a."id" FROM "DEV"."tableA" a ;
创建test环境的freesql实例后,查询语句为:
SELECT a."id" FROM "TEST"."tableA" a;
但这之后,哪怕是使用 GetInstance("DEV")获取到dev环境对应freesql,查询得到的语句仍然是:
SELECT a."id" FROM "TEST"."tableA" a;

以下为查询时的语句:

using var dbcontext = new FreeSqlContext(FreeSQL.GetInstance(env));
var q = dbcontext.Configs.Where(c => c.Status == ConfigStatus.Enabled);
#if DEBUG
string sql = q.ToSql();
Console.WriteLine($"search@{env}:" + sql);
#endif
return await q.ToListAsync();

过程中监控了每次查询时使用的freesql,freesql.aop,freesql.ado.connectionstring,这些对象确实是对应环境的实例信息,但是生成的sql查询语句中的表名只适用了最后一次创建的freesql中的aop配置;

以下为freesql实例创建,AOP配置及缓存相关逻辑

public static class FreeSQL
{
      private static IFreeSql _freesql;
      private static Dictionary<string, IFreeSql> _envFreesqls = new ();
      private static object _lock = new object();

      static FreeSQL()
      {
          _freesql = new FreeSql.FreeSqlBuilder()
                      .UseMappingPriority(MappingPriorityType.Attribute,MappingPriorityType.FluentApi,MappingPriorityType.Aop)
                      .UseConnectionString(ProviderToFreesqlDbType(DbProvider), DbConnection)
                      .Build();
          FluentApi.Config(_freesql);
          _freesql.Aop.ConfigEntity+=(s,e)=>{
              var name = e.EntityType.GetCustomAttribute<TableAttribute>()?.Name ?? //特性
                          _freesql.CodeFirst.GetConfigEntity(e.EntityType)?.Name ?? //FluentApi
                          e.EntityType.Name;
              if (name.Contains(".") == false) {
                  e.ModifyResult.Name="DEV." + name;
              }
          };
          EnsureTables.Ensure(_freesql);
      }

      public static IFreeSql Instance{
          get{
              return _freesql;
          }
      }

      /// <summary>
      /// 根据环境配置的字符串返回freesql 实例
      /// </summary>
      /// <param name="env"></param>
      /// <returns></returns>
      public static IFreeSql GetInstance(string env)
      {
          if (string.IsNullOrEmpty(env))
          {
              return Instance;
          }

          var provider = Global.Config[$"db:env:{env}:provider"];
          var conn = Global.Config[$"db:env:{env}:conn"];

          var key = $"{env}-{provider}";

          if (_envFreesqls.ContainsKey(key))
          {
              var cachedSql = _envFreesqls[key];
 #if DEBUG
              Console.WriteLine(@$"resolve from cache@env:{env} freesql instance.
key:{key}
conn:{ conn }
sql-hash:{cachedSql.GetHashCode()}
sql-conn:{cachedSql.Ado.ConnectionString}
aop-hash:{cachedSql.Aop.GetHashCode()}
");
#endif
              
              return cachedSql;
          }

          lock (_lock)
          {
              if (_envFreesqls.ContainsKey(key))
              {
                  return _envFreesqls[key];
              }

              var sql = new FreeSql.FreeSqlBuilder()
                      .UseMappingPriority(MappingPriorityType.Attribute, MappingPriorityType.FluentApi, MappingPriorityType.Aop)
                      .UseConnectionString(ProviderToFreesqlDbType(provider), conn)
                      .Build();
              FluentApi.Config(sql);
              
              sql.Aop.ConfigEntity+=(s,e)=>{
                  var name = e.EntityType.GetCustomAttribute<TableAttribute>()?.Name ?? //特性
                              sql.CodeFirst.GetConfigEntity(e.EntityType)?.Name ?? //FluentApi
                              e.EntityType.Name;
                  if (name.Contains(".") == false) {
                      e.ModifyResult.Name = $"{env}.{name}";
                  }
              };

              EnsureTables.Ensure(sql, env); // 如果不存在对应schema或数据表,那么创建对应的schema和tables
              _envFreesqls.Add(key, sql);
              return sql;
          }
      }

      private static string DbProvider{
          get{
              return Global.Config["db:env:DEV:provider"] ?? Global.Config["db:provider"];
          }
      }
      private static string DbConnection{
          get{
              return Global.Config["db:env:DEV:conn"] ?? Global.Config["db:conn"];
          }
      }
      
      private static FreeSql.DataType ProviderToFreesqlDbType(string provider)
      {
          switch (provider.ToLower())
          {
              case "sqlite":
                  return FreeSql.DataType.Sqlite;
              case "mysql":
                  return FreeSql.DataType.MySql;
              case "sqlserver":
                  return FreeSql.DataType.SqlServer;
              case "npgsql":
                  return FreeSql.DataType.PostgreSQL;
              case "postgresql":
                  return FreeSql.DataType.PostgreSQL;
              case "oracle":
                  return FreeSql.DataType.Oracle;
              default:
                  break;
          }

          return FreeSql.DataType.Sqlite;
      }
  }

数据库版本

PostgresSQL: 14.0

安装的Nuget包

PackageReference Include="FreeSql" Version="3.2.693"
PackageReference Include="FreeSql.DbContext" Version="3.2.693"
PackageReference Include="FreeSql.Provider.MySqlConnector" Version="3.2.693"
PackageReference Include="FreeSql.Provider.Oracle" Version="3.2.693"
PackageReference Include="FreeSql.Provider.PostgreSQL" Version="3.2.693"
PackageReference Include="FreeSql.Provider.Sqlite" Version="3.2.693"
PackageReference Include="FreeSql.Provider.SqlServer" Version="3.2.693"
PackageReference Include="Microsoft.Data.SqlClient" Version="4.0.0"
PackageReference Include="Microsoft.Data.SqlClient.SNI.runtime" Version="4.0.0"

.net framework/. net core? 及具体版本

net6.0

@2881099
Copy link
Collaborator

2881099 commented Jun 20, 2023

目前确实是这样,同一个DataType存储的实体类的映射内容是同一份,不是与IFreeSql关联。

@mHalo
Copy link
Author

mHalo commented Jun 21, 2023

好的👌🏻,谢啦~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants