diff --git a/FreeSql.Extensions.EFCoreModelBuilder/CodeFirstExtensions.cs b/FreeSql.Extensions.EFCoreModelBuilder/CodeFirstExtensions.cs
new file mode 100644
index 00000000..a563e033
--- /dev/null
+++ b/FreeSql.Extensions.EFCoreModelBuilder/CodeFirstExtensions.cs
@@ -0,0 +1,64 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Linq;
+
+namespace FreeSql.Extensions.EFCoreModelBuilder {
+
+ public static class CodeFirstExtensions {
+
+ public static void ConfigEntity(this ICodeFirst codeFirst, ModelBuilder modelBuilder) {
+
+ foreach (var type in modelBuilder.Model.GetEntityTypes()) {
+
+ codeFirst.ConfigEntity(type.ClrType, a => {
+
+ //表名
+ var relationalTableName = type.FindAnnotation("Relational:TableName");
+ if (relationalTableName != null) {
+ a.Name(relationalTableName.Value?.ToString() ?? type.ClrType.Name);
+ }
+
+ foreach (var prop in type.GetProperties()) {
+
+ var freeProp = a.Property(prop.Name);
+
+ //列名
+ var relationalColumnName = prop.FindAnnotation("Relational:ColumnName");
+ if (relationalColumnName != null) {
+
+ freeProp.Name(relationalColumnName.Value?.ToString() ?? prop.Name);
+ }
+
+ //主键
+ freeProp.IsPrimary(prop.IsPrimaryKey());
+
+ //自增
+ freeProp.IsIdentity(prop.GetAnnotations().Where(z =>
+ z.Name == "SqlServer:ValueGenerationStrategy" && z.Value.ToString().Contains("IdentityColumn") //sqlserver 自增
+ || z.Value.ToString().Contains("IdentityColumn") //其他数据库实现未经测试
+ ).Any());
+
+ //可空
+ freeProp.IsNullable(prop.AfterSaveBehavior != Microsoft.EntityFrameworkCore.Metadata.PropertySaveBehavior.Throw);
+
+ //类型
+ var relationalColumnType = prop.FindAnnotation("Relational:ColumnType");
+ if (relationalColumnType != null) {
+
+ var dbType = relationalColumnType.ToString();
+
+ if (!string.IsNullOrEmpty(dbType)) {
+
+ var maxLength = prop.FindAnnotation("MaxLength");
+ if (maxLength != null)
+ dbType += $"({maxLength})";
+
+ freeProp.DbType(dbType);
+ }
+ }
+ }
+ });
+ }
+ }
+ }
+}
diff --git a/FreeSql.Extensions.EFCoreModelBuilder/FreeSql.Extensions.EFCoreModelBuilder.csproj b/FreeSql.Extensions.EFCoreModelBuilder/FreeSql.Extensions.EFCoreModelBuilder.csproj
new file mode 100644
index 00000000..efc6283c
--- /dev/null
+++ b/FreeSql.Extensions.EFCoreModelBuilder/FreeSql.Extensions.EFCoreModelBuilder.csproj
@@ -0,0 +1,21 @@
+
+
+
+ netstandard2.0
+ 0.0.12
+ FreeSql
+ FreeSql
+ FreeSql ICodeFirst 扩展库,现实从 EFCore FluentAPI/Attribute 读取,从而做到无缝接入已使用 EFCore 项目开发。
+ https://github.com/2881099/FreeSql
+ https://github.com/2881099/FreeSql
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FreeSql.RESTful.Demo/Entity/Song.cs b/FreeSql.RESTful.Demo/Entity/Song.cs
index a01a4f15..817470de 100644
--- a/FreeSql.RESTful.Demo/Entity/Song.cs
+++ b/FreeSql.RESTful.Demo/Entity/Song.cs
@@ -1,10 +1,14 @@
-using System;
+using Microsoft.EntityFrameworkCore;
+using System;
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
namespace FreeSql.RESTful.Demo.Entity {
public class Song {
+
public int Id { get; set; }
public string Title { get; set; }
}
diff --git a/FreeSql.RESTful.Demo/FreeSql.RESTful.Demo.csproj b/FreeSql.RESTful.Demo/FreeSql.RESTful.Demo.csproj
index d6e2e03e..a52d3545 100644
--- a/FreeSql.RESTful.Demo/FreeSql.RESTful.Demo.csproj
+++ b/FreeSql.RESTful.Demo/FreeSql.RESTful.Demo.csproj
@@ -7,6 +7,8 @@
+
+
diff --git a/FreeSql.RESTful.Demo/Startup.cs b/FreeSql.RESTful.Demo/Startup.cs
index 011d96b6..64b60821 100644
--- a/FreeSql.RESTful.Demo/Startup.cs
+++ b/FreeSql.RESTful.Demo/Startup.cs
@@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
diff --git a/FreeSql.Tests/DataAnnotations/FluentTest.cs b/FreeSql.Tests/DataAnnotations/FluentTest.cs
index 5c5ae522..47f3493f 100644
--- a/FreeSql.Tests/DataAnnotations/FluentTest.cs
+++ b/FreeSql.Tests/DataAnnotations/FluentTest.cs
@@ -6,16 +6,24 @@ namespace FreeSql.Tests.DataAnnotations {
[Fact]
public void Fluent() {
g.mysql.CodeFirst
- .ConfigEntity(a => {
- a.Name("xxdkdkdk1").SelectFilter("a.Id22 > 0");
- a.Property(b => b.Id).Name("Id22").IsIdentity(true);
- a.Property(b => b.name).DbType("varchar(100)").IsNullable(true);
+ //.ConfigEntity(a => {
+ // a.Name("xxdkdkdk1").SelectFilter("a.Id22 > 0");
+ // a.Property(b => b.Id).Name("Id22").IsIdentity(true);
+ // a.Property(b => b.name).DbType("varchar(100)").IsNullable(true);
+ //})
+
+ .ConfigEntity(typeof(TestFluenttb1), a => {
+ a.Name("xxdkdkdk1222").SelectFilter("a.Id22 > 1");
+ a.Property("Id").Name("Id22dd").IsIdentity(true);
+ a.Property("Name").DbType("varchar(101)").IsNullable(true);
})
+
.ConfigEntity(a => {
a.Name("xxdkdkdk2").SelectFilter("a.Idx > 0");
a.Property(b => b.Id).Name("Id22").IsIdentity(true);
a.Property(b => b.name).DbType("varchar(100)").IsNullable(true);
- });
+ })
+ ;
var ddl1 = g.mysql.CodeFirst.GetComparisonDDLStatements();
var ddl2 = g.mysql.CodeFirst.GetComparisonDDLStatements();
diff --git a/FreeSql.sln b/FreeSql.sln
index 1beaf6a3..198f1157 100644
--- a/FreeSql.sln
+++ b/FreeSql.sln
@@ -18,6 +18,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Tests.PerformanceTe
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.RESTful.Demo", "FreeSql.RESTful.Demo\FreeSql.RESTful.Demo.csproj", "{A749092B-4C21-4087-B33D-0FBD4DA51C24}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FreeSql.Extensions.EFCoreModelBuilder", "FreeSql.Extensions.EFCoreModelBuilder\FreeSql.Extensions.EFCoreModelBuilder.csproj", "{490CC8AF-C47C-4139-AED7-4FB6502F622B}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -88,6 +90,18 @@ Global
{A749092B-4C21-4087-B33D-0FBD4DA51C24}.Release|x64.Build.0 = Release|Any CPU
{A749092B-4C21-4087-B33D-0FBD4DA51C24}.Release|x86.ActiveCfg = Release|Any CPU
{A749092B-4C21-4087-B33D-0FBD4DA51C24}.Release|x86.Build.0 = Release|Any CPU
+ {490CC8AF-C47C-4139-AED7-4FB6502F622B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {490CC8AF-C47C-4139-AED7-4FB6502F622B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {490CC8AF-C47C-4139-AED7-4FB6502F622B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {490CC8AF-C47C-4139-AED7-4FB6502F622B}.Debug|x64.Build.0 = Debug|Any CPU
+ {490CC8AF-C47C-4139-AED7-4FB6502F622B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {490CC8AF-C47C-4139-AED7-4FB6502F622B}.Debug|x86.Build.0 = Debug|Any CPU
+ {490CC8AF-C47C-4139-AED7-4FB6502F622B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {490CC8AF-C47C-4139-AED7-4FB6502F622B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {490CC8AF-C47C-4139-AED7-4FB6502F622B}.Release|x64.ActiveCfg = Release|Any CPU
+ {490CC8AF-C47C-4139-AED7-4FB6502F622B}.Release|x64.Build.0 = Release|Any CPU
+ {490CC8AF-C47C-4139-AED7-4FB6502F622B}.Release|x86.ActiveCfg = Release|Any CPU
+ {490CC8AF-C47C-4139-AED7-4FB6502F622B}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/FreeSql/DataAnnotations/ColumnFluent.cs b/FreeSql/DataAnnotations/ColumnFluent.cs
index 3b9ffe56..a5e63721 100644
--- a/FreeSql/DataAnnotations/ColumnFluent.cs
+++ b/FreeSql/DataAnnotations/ColumnFluent.cs
@@ -1,7 +1,7 @@
using System;
namespace FreeSql.DataAnnotations {
- public class ColumnFluent {
+ public class ColumnFluent {
public ColumnFluent(ColumnAttribute column) {
_column = column;
@@ -11,21 +11,21 @@ namespace FreeSql.DataAnnotations {
///
/// 数据库列名
///
- public ColumnFluent Name(string value) {
+ public ColumnFluent Name(string value) {
_column.Name = value;
return this;
}
///
/// 指定数据库旧的列名,修改实体属性命名时,同时设置此参数为修改之前的值,CodeFirst才可以正确修改数据库字段;否则将视为【新增字段】
///
- public ColumnFluent OldName(string value) {
+ public ColumnFluent OldName(string value) {
_column.OldName = value;
return this;
}
///
/// 数据库类型,如: varchar(255)
///
- public ColumnFluent DbType(string value) {
+ public ColumnFluent DbType(string value) {
_column.DbType = value;
return this;
}
@@ -33,20 +33,20 @@ namespace FreeSql.DataAnnotations {
///
/// 主键
///
- public ColumnFluent IsPrimary(bool value) {
+ public ColumnFluent IsPrimary(bool value) {
_column.IsPrimary = value;
return this;
}
/// 自增标识
///
- public ColumnFluent IsIdentity(bool value) {
+ public ColumnFluent IsIdentity(bool value) {
_column.IsIdentity = value;
return this;
}
///
/// 是否可DBNull
///
- public ColumnFluent IsNullable(bool value) {
+ public ColumnFluent IsNullable(bool value) {
_column.IsNullable = value;
return this;
}
diff --git a/FreeSql/DataAnnotations/TableAttribute.cs b/FreeSql/DataAnnotations/TableAttribute.cs
index 1210d8d8..fe6788a5 100644
--- a/FreeSql/DataAnnotations/TableAttribute.cs
+++ b/FreeSql/DataAnnotations/TableAttribute.cs
@@ -17,6 +17,6 @@ namespace FreeSql.DataAnnotations {
///
public string SelectFilter { get; set; }
- internal ConcurrentDictionary _columns => new ConcurrentDictionary(StringComparer.CurrentCultureIgnoreCase);
+ internal ConcurrentDictionary _columns { get; } = new ConcurrentDictionary(StringComparer.CurrentCultureIgnoreCase);
}
}
diff --git a/FreeSql/DataAnnotations/TableFluent.cs b/FreeSql/DataAnnotations/TableFluent.cs
index 2860f1df..944d380d 100644
--- a/FreeSql/DataAnnotations/TableFluent.cs
+++ b/FreeSql/DataAnnotations/TableFluent.cs
@@ -1,9 +1,51 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
+using System.Linq;
using System.Linq.Expressions;
+using System.Reflection;
namespace FreeSql.DataAnnotations {
+ public class TableFluent {
+
+ public TableFluent(Type entityType, TableAttribute table) {
+ _entityType = entityType;
+ _properties = _entityType.GetProperties().ToDictionary(a => a.Name, a => a, StringComparer.CurrentCultureIgnoreCase);
+ _table = table;
+ }
+
+ Type _entityType;
+ Dictionary _properties;
+ TableAttribute _table;
+ ///
+ /// 数据库表名
+ ///
+ public TableFluent Name(string value) {
+ _table.Name = value;
+ return this;
+ }
+ ///
+ /// 指定数据库旧的表名,修改实体命名时,同时设置此参数为修改之前的值,CodeFirst才可以正确修改数据库表;否则将视为【创建新表】
+ ///
+ public TableFluent OldName(string value) {
+ _table.OldName = value;
+ return this;
+ }
+ ///
+ /// 查询过滤SQL,实现类似 a.IsDeleted = 1 功能
+ ///
+ public TableFluent SelectFilter(string value) {
+ _table.SelectFilter = value;
+ return this;
+ }
+
+ public ColumnFluent Property(string proto) {
+ if (_properties.ContainsKey(proto) == false) throw new KeyNotFoundException($"找不到属性名 {proto}");
+ var col = _table._columns.GetOrAdd(proto, name => new ColumnAttribute { Name = proto });
+ return new ColumnFluent(col);
+ }
+ }
+
public class TableFluent {
public TableFluent(TableAttribute table) {
@@ -33,11 +75,11 @@ namespace FreeSql.DataAnnotations {
return this;
}
- public ColumnFluent Property(Expression> column) {
+ public ColumnFluent Property(Expression> column) {
var proto = (column.Body as MemberExpression)?.Member;
if (proto == null) throw new FormatException($"错误的表达式格式 {column}");
var col = _table._columns.GetOrAdd(proto.Name, name => new ColumnAttribute { Name = proto.Name });
- return new ColumnFluent(col);
+ return new ColumnFluent(col);
}
}
}
diff --git a/FreeSql/FreeSql.csproj b/FreeSql/FreeSql.csproj
index 96704b3a..718f746b 100644
--- a/FreeSql/FreeSql.csproj
+++ b/FreeSql/FreeSql.csproj
@@ -2,7 +2,7 @@
netstandard2.0
- 0.0.12
+ 0.0.13
true
YeXiangQin
打造 .NETCore 最方便的 ORM,DbFirst 与 CodeFirst 混合使用,提供从实体同步数据库,或者从数据库生成实体代码,支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite 数据库。
diff --git a/FreeSql/Interface/ICodeFirst.cs b/FreeSql/Interface/ICodeFirst.cs
index e333da97..50cc363c 100644
--- a/FreeSql/Interface/ICodeFirst.cs
+++ b/FreeSql/Interface/ICodeFirst.cs
@@ -50,5 +50,6 @@ namespace FreeSql {
///
(int type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfo(Type type);
ICodeFirst ConfigEntity(Action> entity);
+ ICodeFirst ConfigEntity(Type type, Action entity);
}
}
diff --git a/FreeSql/Internal/CommonUtils.cs b/FreeSql/Internal/CommonUtils.cs
index dfe91af9..7be2acd4 100644
--- a/FreeSql/Internal/CommonUtils.cs
+++ b/FreeSql/Internal/CommonUtils.cs
@@ -40,9 +40,15 @@ namespace FreeSql.Internal {
entity?.Invoke(fluent);
return _orm.CodeFirst;
}
- internal TableAttribute GetEntityTableAttribute(Type entityType) {
- var attr = entityType.GetCustomAttributes(typeof(TableAttribute), false).LastOrDefault() as TableAttribute;
- if (dicConfigEntity.TryGetValue(entityType, out var trytb) == false) return attr;
+ internal ICodeFirst ConfigEntity(Type type, Action entity) {
+ var table = dicConfigEntity.GetOrAdd(type, new TableAttribute());
+ var fluent = new TableFluent(type, table);
+ entity?.Invoke(fluent);
+ return _orm.CodeFirst;
+ }
+ internal TableAttribute GetEntityTableAttribute(Type type) {
+ var attr = type.GetCustomAttributes(typeof(TableAttribute), false).LastOrDefault() as TableAttribute;
+ if (dicConfigEntity.TryGetValue(type, out var trytb) == false) return attr;
if (attr == null) attr = new TableAttribute();
if (string.IsNullOrEmpty(attr.Name)) attr.Name = trytb.Name;
@@ -50,9 +56,9 @@ namespace FreeSql.Internal {
if (string.IsNullOrEmpty(attr.SelectFilter)) attr.SelectFilter = trytb.SelectFilter;
return attr;
}
- internal ColumnAttribute GetEntityColumnAttribute(Type entityType, PropertyInfo proto) {
+ internal ColumnAttribute GetEntityColumnAttribute(Type type, PropertyInfo proto) {
var attr = proto.GetCustomAttributes(typeof(ColumnAttribute), false).LastOrDefault() as ColumnAttribute;
- if (dicConfigEntity.TryGetValue(entityType, out var trytb) == false) return attr;
+ if (dicConfigEntity.TryGetValue(type, out var trytb) == false) return attr;
if (trytb._columns.TryGetValue(proto.Name, out var trycol) == false) return attr;
if (attr == null) attr = new ColumnAttribute();
diff --git a/FreeSql/MySql/MySqlCodeFirst.cs b/FreeSql/MySql/MySqlCodeFirst.cs
index 5d21c230..534a29ef 100644
--- a/FreeSql/MySql/MySqlCodeFirst.cs
+++ b/FreeSql/MySql/MySqlCodeFirst.cs
@@ -272,5 +272,6 @@ where a.table_schema in ({0}) and a.table_name in ({1})".FormatMySql(tboldname ?
}
}
public ICodeFirst ConfigEntity(Action> entity) => _commonUtils.ConfigEntity(entity);
+ public ICodeFirst ConfigEntity(Type type, Action entity) => _commonUtils.ConfigEntity(type, entity);
}
}
\ No newline at end of file
diff --git a/FreeSql/Oracle/OracleCodeFirst.cs b/FreeSql/Oracle/OracleCodeFirst.cs
index dc88797d..369d6808 100644
--- a/FreeSql/Oracle/OracleCodeFirst.cs
+++ b/FreeSql/Oracle/OracleCodeFirst.cs
@@ -310,5 +310,6 @@ where owner={{0}} and table_name={{1}}".FormatOracleSQL(tboldname ?? tbname);
}
}
public ICodeFirst ConfigEntity(Action> entity) => _commonUtils.ConfigEntity(entity);
+ public ICodeFirst ConfigEntity(Type type, Action entity) => _commonUtils.ConfigEntity(type, entity);
}
}
\ No newline at end of file
diff --git a/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs b/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs
index e277dc31..49c808bb 100644
--- a/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs
+++ b/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs
@@ -324,5 +324,6 @@ where pg_namespace.nspname={0} and pg_class.relname={1} and pg_constraint.contyp
}
}
public ICodeFirst ConfigEntity(Action> entity) => _commonUtils.ConfigEntity(entity);
+ public ICodeFirst ConfigEntity(Type type, Action entity) => _commonUtils.ConfigEntity(type, entity);
}
}
\ No newline at end of file
diff --git a/FreeSql/SqlServer/SqlServerCodeFirst.cs b/FreeSql/SqlServer/SqlServerCodeFirst.cs
index c0b491cb..1e69912a 100644
--- a/FreeSql/SqlServer/SqlServerCodeFirst.cs
+++ b/FreeSql/SqlServer/SqlServerCodeFirst.cs
@@ -282,5 +282,6 @@ use " + database, tboldname ?? tbname);
}
}
public ICodeFirst ConfigEntity(Action> entity) => _commonUtils.ConfigEntity(entity);
+ public ICodeFirst ConfigEntity(Type type, Action entity) => _commonUtils.ConfigEntity(type, entity);
}
}
\ No newline at end of file
diff --git a/FreeSql/Sqlite/SqliteCodeFirst.cs b/FreeSql/Sqlite/SqliteCodeFirst.cs
index ca8a61d6..54b31bff 100644
--- a/FreeSql/Sqlite/SqliteCodeFirst.cs
+++ b/FreeSql/Sqlite/SqliteCodeFirst.cs
@@ -240,5 +240,6 @@ namespace FreeSql.Sqlite {
}
}
public ICodeFirst ConfigEntity(Action> entity) => _commonUtils.ConfigEntity(entity);
+ public ICodeFirst ConfigEntity(Type type, Action entity) => _commonUtils.ConfigEntity(type, entity);
}
}
\ No newline at end of file