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

FluentApi 能否实现自定义特性(表前辍) #1247

Closed
lxh023 opened this issue Sep 15, 2022 · 10 comments
Closed

FluentApi 能否实现自定义特性(表前辍) #1247

lxh023 opened this issue Sep 15, 2022 · 10 comments

Comments

@lxh023
Copy link

lxh023 commented Sep 15, 2022

Feature 特性

能否在FluentApi中加入自定义特性支持

简要描述原因

#407 回复启发,在https://github.com/dotnetcore/FreeSql/wiki/FluentApi
中,可以引用默认的特性,而目前因为Table属性会发生失效的情况,通过折中方式实现了。

freesql.Aop.ConfigEntity += (s, e) =>
            {
                //修改默认的模式名称,默认为public
          
                var attr=e.EntityType.GetCustomAttributes(typeof(MyTableAttribute), false).FirstOrDefault() as MyTableAttribute;
                if (attr != null)
                    e.ModifyResult.Name = "xxxxx."+attr.TableName; //自定义特性表名

                //if (!e.ModifyResult.Name.Contains("."))
                //    e.ModifyResult.Name = "xxxxx." + e.ModifyResult.Name;
                //System.Console.WriteLine(e.ModifyResult.Name);
            };
----------------------------------------------------------
[MyTable(TableName = "flow_model_cfg")]
[Table(Name="flow_model_cfg")]
public class FlowModelCfg {...}
----------------------------------------------------------
 public class MyTableAttribute:System.Attribute
    {
        public string TableName { get; set; }
   }

但个人更倾向于FluentApi,而不是实体特性,这样不对实体类产生太多的侵入性。

使用场景

针对各种个性化特性的场景

@lxh023
Copy link
Author

lxh023 commented Sep 16, 2022

补充一下,是针对postgresql场景,发现不但表名Name失效,连列名也失效了,
还要增加

fsql.Aop.ConfigEntityProperty += (s, e) => {
  var attr = e.Property.GetCustomAttributes(typeof(MyColumnAttribute), false).FirstOrDefault() as MyColumnAttribute;
  if (attr != null &&  e.ModifyResult.Name != attr.Name)
    e.ModifyResult.Name = attr.Name; //字段名
};

@2881099
Copy link
Collaborator

2881099 commented Sep 16, 2022

freesql.Aop.ConfigEntity+=(s,e)=>{
    var name = e.EntityType.GetCustomAttribute<TableAttribute>()?.Name ?? e.EntityType.Name;
    if (name.Contains(".") == false)
        e.ModifyResult.Name="xxxxx." + name;
}

@lxh023
Copy link
Author

lxh023 commented Sep 16, 2022

Snipaste_2022-09-16_12-30-38

@2881099
Copy link
Collaborator

2881099 commented Sep 16, 2022

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="xxxxx." + name;
};

@lxh023
Copy link
Author

lxh023 commented Sep 17, 2022

大佬牛逼,测试可以了,但还是有个问题 。

fsql.Aop.ConfigEntityProperty += (s, e) => {
  var attr = e.Property.GetCustomAttributes(typeof(MyColumnAttribute), false).FirstOrDefault() as MyColumnAttribute;
  if (attr != null &&  e.ModifyResult.Name != attr.Name)
    e.ModifyResult.Name = attr.Name; //字段名
};

这部分FluentApi代码,不知道要怎么实现,查了一下,ICodeFirst好像没有获取ColumnAttributer的方法

@2881099
Copy link
Collaborator

2881099 commented Sep 17, 2022

ColumnAttribute 直接用反射获取

@lxh023
Copy link
Author

lxh023 commented Sep 17, 2022

Snipaste_2022-09-18_01-46-58

   _PostgreSqlFreeSql.Aop.ConfigEntityProperty += (s, e) =>
            {
                var attr = e.Property.GetCustomAttributes(typeof(ColumnAttribute), false).FirstOrDefault() as ColumnAttribute;
                if (attr != null
                   && (string.IsNullOrEmpty(e.ModifyResult.Name)
                    || (!string.IsNullOrEmpty(e.ModifyResult.Name) && !e.ModifyResult.Name.Equals(attr.Name))))
                    e.ModifyResult.Name =   attr.Name;
            };

看文档的方法,反射获取为空,大佬还有其他办法吗?

@2881099
Copy link
Collaborator

2881099 commented Sep 18, 2022

看来还是得发个版本,前面给你的方案有个私有成员

v3.2.670-preview22020918 最终方案:

freesql.Aop.ConfigEntity += (s, e) =>
{
    var name = e.ModifyResult.Name; //可直接获取 FluentApi/Attirubte 生效的内容
    if (name.Contains(".") == false)
        e.ModifyResult.Name="xxxxx." + name;
};
freesql.Aop.ConfigEntityProperty += (s, e) =>
{
    var name = e.ModifyResult.Name; //可直接获取 FluentApi/Attirubte 生效的内容
};

@lxh023
Copy link
Author

lxh023 commented Sep 18, 2022

这个还是没办法出来。读了一下源码,并加到项目上打断点,发现有几个奇怪的地方:
1、\FreeSql\Internal\CommonUtils.cs,这个文件,_mappingPriorityTypes 似乎写死了,并没有应用FreeSqlBuilder.UseMappingPriority的传值
2、\FreeSql\DataAnnotations\TableAttribute.cs,这个TableAttribute类并没有提供_columns的方法,兄弟不才,加了一个函数getColumns()
Snipaste_2022-09-19_01-11-44

  public ConcurrentDictionary getColumns() {   return _columns;  }

最终试验成功
Snipaste_2022-09-19_01-14-05
关键代码如下:

_PostgreSqlFreeSql.Aop.ConfigEntity += (s, e) =>
 {         
      var attr = e.EntityType.GetCustomAttribute()?? //特性
                     _PostgreSqlFreeSql.CodeFirst.GetConfigEntity(e.EntityType); ////FluentApi
        if (attr != null
                   && (string.IsNullOrEmpty(e.ModifyResult.Name)
                    || (!string.IsNullOrEmpty(e.ModifyResult.Name) && !e.ModifyResult.Name.Equals(attr.Name))))
                    e.ModifyResult.Name = "qzhalinxh." + attr.Name;
}

 _PostgreSqlFreeSql.Aop.ConfigEntityProperty += (s, e) =>
{
 var attr = _PostgreSqlFreeSql.CodeFirst.GetConfigEntity(e.EntityType);
                if (attr == null) return;
                var columns = attr.getColumns().Where(p => p.Key.ToLower() == 
               e.ModifyResult.Name.ToLower()).FirstOrDefault().Value;
                
          if (attr != null && columns!=null && columns.Name != e.ModifyResult.Name)
                    e.ModifyResult.Name = columns.Name;
}

请评估一下能否在TableAttribute类增加一个 getColumns函数来获取列信息?

@2881099
Copy link
Collaborator

2881099 commented Sep 19, 2022

1、FreeSqlBuilder Build 时会重新设置 _commonUtils._mappingPriorityTypes
2、昨天回复正是不愿意增加 getColumns 类似的方法才回复的

刚才测试结果:

[Table(Name = "AAA_attr")]
public class AAA
{
    [Column(Name = "aa_attr")]
    public int aa { get; set; }
}

var fsql = new FreeSql.FreeSqlBuilder()
    .UseConnectionString(FreeSql.DataType.Sqlite, "data source=:memory:")
    .UseAutoSyncStructure(true)
    .UseNoneCommandParameter(true)
    .UseMappingPriority(MappingPriorityType.Attribute, MappingPriorityType.FluentApi, MappingPriorityType.Aop)
    .Build();

fsql.Aop.ConfigEntity += (_, e) =>
{
    Console.WriteLine("Aop.ConfigEntity: " + e.ModifyResult.Name);
};
fsql.Aop.ConfigEntityProperty += (_, e) =>
{
    Console.WriteLine("Aop.ConfigEntityProperty: " + e.ModifyResult.Name);
};
fsql.Select<AAA>();

fsql.CodeFirst.ConfigEntity<AAA>(t =>
{
    t.Name("AAA_fluentapi");
    t.Property(a => a.aa).Name("AA_fluentapi");
});
fsql.Select<AAA>();

打印:

Aop.ConfigEntity: AAA_attr
Aop.ConfigEntityProperty: aa_attr
Aop.ConfigEntity:
Aop.ConfigEntity: AAA_fluentapi
Aop.ConfigEntityProperty: AA_fluentapi
Aop.ConfigEntity:

UseMappingPriority 优先级是 Attribute 最小,其次 FluentApi,最大 Aop。

FluentApi 可以复盖 Attribute 设置,Aop 可以复盖 FluentApi 设置。

上面两个为空,是获取 IndexAttribute 造成的,对 TableAttribute 结果没有影响。

第一次 .Select<T> 获取元数据,缓存起来

fluentapi 会移除元数据缓存,因此第二次 .Select<T> 又获取了一次元数据,再缓存起来。

2881099 added a commit that referenced this issue Sep 24, 2022
2881099 added a commit that referenced this issue Sep 25, 2022
@2881099 2881099 closed this as completed Oct 2, 2022
@2881099 2881099 changed the title FluentApi能否实现自定义特性 FluentApi 能否实现自定义特性(表前辍) Nov 8, 2022
2881099 added a commit that referenced this issue Jul 15, 2024
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