diff --git a/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs b/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs index ed0ee7f2..409c553a 100644 --- a/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs +++ b/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs @@ -10,28 +10,39 @@ namespace FreeSql.Tests.MySql { ISelect select => g.mysql.Select(); [Table(Name = "tb_topic")] - class Topic { + public class Topic { [Column(IsIdentity = true, IsPrimary = true)] public int Id { get; set; } public int Clicks { get; set; } public int TestTypeInfoGuid { get; set; } - public TestTypeInfo Type { get; set; } + + public int TypeGuid { get; set; } + public virtual TestTypeInfo Type { get; set; } public string Title { get; set; } public DateTime CreateTime { get; set; } } - class TestTypeInfo { + public class TestTypeInfo { + [Column(IsIdentity = true)] public int Guid { get; set; } public int ParentId { get; set; } public TestTypeParentInfo Parent { get; set; } public string Name { get; set; } } - class TestTypeParentInfo { + public class TestTypeParentInfo { + [Column(IsIdentity = true)] public int Id { get; set; } public string Name { get; set; } public List Types { get; set; } } + [Fact] + public void Lazy() { + Topic t = g.mysql.Select(2).ToOne(); + Topic tz = g.mysql.Select(2).ToOne(); + var tzType = tz.Type; + } + [Fact] public void ToList() { var t0 = select.Limit(50).ToList(); diff --git a/FreeSql.Tests/g.cs b/FreeSql.Tests/g.cs index cc319fe5..79360ff6 100644 --- a/FreeSql.Tests/g.cs +++ b/FreeSql.Tests/g.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Text; @@ -11,7 +12,7 @@ public class g { .UseMonitorCommand( cmd => { - Console.WriteLine(cmd.CommandText); + Trace.WriteLine(cmd.CommandText); }, //监听SQL命令对象,在执行前 (cmd, traceLog) => { Console.WriteLine(traceLog); diff --git a/FreeSql/FreeSqlBuilder.cs b/FreeSql/FreeSqlBuilder.cs index 92bd8990..3ffde3b3 100644 --- a/FreeSql/FreeSqlBuilder.cs +++ b/FreeSql/FreeSqlBuilder.cs @@ -14,6 +14,7 @@ namespace FreeSql { string[] _slaveConnectionString; bool _isAutoSyncStructure = false; bool _isSyncStructureToLower = false; + bool _isLazyLoading = false; Action _aopCommandExecuting = null; Action _aopCommandExecuted = null; @@ -75,6 +76,15 @@ namespace FreeSql { return this; } /// + /// 延时加载导航属性对象,导航属性需要声明 virtual + /// + /// + /// + public FreeSqlBuilder UseLazyLoading(bool value) { + _isLazyLoading = value; + return this; + } + /// /// 监视数据库命令对象 /// /// 执行前 @@ -98,6 +108,7 @@ namespace FreeSql { if (ret != null) { ret.CodeFirst.IsAutoSyncStructure = _isAutoSyncStructure; ret.CodeFirst.IsSyncStructureToLower = _isSyncStructureToLower; + ret.CodeFirst.IsLazyLoading = _isLazyLoading; var ado = ret.Ado as Internal.CommonProvider.AdoProvider; ado.AopCommandExecuting += _aopCommandExecuting; ado.AopCommandExecuted += _aopCommandExecuted; diff --git a/FreeSql/Generator/TemplateEngin.cs b/FreeSql/Generator/TemplateEngin.cs index 9d8a905b..74dcf3cb 100644 --- a/FreeSql/Generator/TemplateEngin.cs +++ b/FreeSql/Generator/TemplateEngin.cs @@ -544,8 +544,7 @@ return rTn;"); var type = assemly.DefinedTypes.Where(a => a.FullName.EndsWith(typename)).FirstOrDefault(); return Activator.CreateInstance(type) as ITemplateOutput; } - static ConcurrentDictionary _compiler_objs = new ConcurrentDictionary(); - static Lazy _compiler = new Lazy(() => { + internal static Lazy _compiler = new Lazy(() => { var dlls = Directory.GetFiles(Directory.GetParent(Type.GetType("IFreeSql, FreeSql").Assembly.Location).FullName, "*.dll"); var compiler = new CSScriptLib.RoslynEvaluator(); compiler.DisableReferencingFromCode = false; diff --git a/FreeSql/Interface/ICodeFirst.cs b/FreeSql/Interface/ICodeFirst.cs index c0f33c83..527646a0 100644 --- a/FreeSql/Interface/ICodeFirst.cs +++ b/FreeSql/Interface/ICodeFirst.cs @@ -12,6 +12,10 @@ namespace FreeSql { /// 转小写同步结构 /// bool IsSyncStructureToLower { get; set; } + /// + /// 延时加载导航属性对象,导航属性需要声明 virtual + /// + bool IsLazyLoading { get; set; } /// /// 将实体类型与数据库对比,返回DDL语句 diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs index 20895c9c..758379c1 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs @@ -249,9 +249,10 @@ namespace FreeSql.Internal.CommonProvider { public Func Read { get; set; } } protected GetAllFieldExpressionTreeInfo GetAllFieldExpressionTree() { - var key = string.Join("+", _tables.Select(a => $"{a.Table.DbName}-{a.Alias}")); - return _dicGetAllFieldExpressionTree.GetOrAdd(key, s => { - var type = _tables.First().Table.Type; + return _dicGetAllFieldExpressionTree.GetOrAdd(string.Join("+", _tables.Select(a => $"{a.Table.DbName}-{a.Alias}")), s => { + var tb1 = _tables.First().Table; + var type = tb1.TypeLazy ?? tb1.Type; + var props = tb1.Properties; var rowExp = Expression.Parameter(typeof(DbDataReader), "row"); var returnTarget = Expression.Label(type); @@ -266,14 +267,14 @@ namespace FreeSql.Internal.CommonProvider { Expression.Assign(retExp, Expression.New(ctor, ctor.GetParameters().Select(a => Expression.Default(a.ParameterType)))), Expression.Assign(dataIndexExp, Expression.Constant(0)) }); + //typeof(Topic).GetMethod("get_Type").IsVirtual var field = new StringBuilder(); var dicfield = new Dictionary(); var tb = _tables.First(); var index = 0; var otherindex = 0; - var ps = _tables.First().Table.Properties; - foreach (var prop in ps.Values) { + foreach (var prop in props.Values) { if (tb.Table.ColumnsByCs.TryGetValue(prop.Name, out var col)) { //普通字段 if (index > 0) field.Append(", "); var quoteName = _commonUtils.QuoteSqlName(col.Attribute.Name); @@ -283,7 +284,7 @@ namespace FreeSql.Internal.CommonProvider { else dicfield.Add(quoteName, true); } else { var tb2 = _tables.Where(a => a.Table.Type == prop.PropertyType && a.Alias.Contains(prop.Name)).FirstOrDefault(); - if (tb2 == null && ps.Where(pw => pw.Value.PropertyType == prop.PropertyType).Count() == 1) tb2 = _tables.Where(a => a.Table.Type == prop.PropertyType).FirstOrDefault(); + if (tb2 == null && props.Where(pw => pw.Value.PropertyType == prop.PropertyType).Count() == 1) tb2 = _tables.Where(a => a.Table.Type == prop.PropertyType).FirstOrDefault(); if (tb2 == null) continue; foreach (var col2 in tb2.Table.Columns.Values) { if (index > 0) field.Append(", "); @@ -333,6 +334,7 @@ namespace FreeSql.Internal.CommonProvider { Expression.Assign(retExp, Expression.Convert(readExpValue, type)) }); } + if (tb1.TypeLazy != null) blockExp.Add(Expression.Call(retExp, tb1.TypeLazySetOrm, Expression.Constant(_orm))); //将 orm 传递给 lazy blockExp.AddRange(new Expression[] { Expression.Return(returnTarget, retExp), Expression.Label(returnTarget, Expression.Default(type)) @@ -344,7 +346,8 @@ namespace FreeSql.Internal.CommonProvider { }); } protected (ReadAnonymousTypeInfo map, string field) GetAllFieldReflection() { - var type = _tables.First().Table.Type; + var tb1 = _tables.First().Table; + var type = tb1.Type; var constructor = _dicConstructor.GetOrAdd(type, s => type.GetConstructor(new Type[0])); var map = new ReadAnonymousTypeInfo { Consturctor = constructor, ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties }; @@ -352,7 +355,7 @@ namespace FreeSql.Internal.CommonProvider { var dicfield = new Dictionary(); var tb = _tables.First(); var index = 0; - var ps = _tables.First().Table.Properties; + var ps = tb1.Properties; foreach (var p in ps.Values) { var child = new ReadAnonymousTypeInfo { Property = p, CsName = p.Name }; if (tb.Table.ColumnsByCs.TryGetValue(p.Name, out var col)) { //普通字段 diff --git a/FreeSql/Internal/CommonUtils.cs b/FreeSql/Internal/CommonUtils.cs index e952a711..d559eb33 100644 --- a/FreeSql/Internal/CommonUtils.cs +++ b/FreeSql/Internal/CommonUtils.cs @@ -22,9 +22,14 @@ namespace FreeSql.Internal { internal abstract string QuoteReadColumn(Type type, string columnName); internal abstract string DbName { get; } - internal ICodeFirst CodeFirst { get; set; } + internal IFreeSql _orm { get; set; } + internal ICodeFirst CodeFirst => _orm.CodeFirst; internal TableInfo GetTableByEntity(Type entity) => Utils.GetTableByEntity(entity, this); + public CommonUtils(IFreeSql orm) { + _orm = orm; + } + internal string WhereObject(TableInfo table, string aliasAndDot, object dywhere) { if (dywhere == null) return ""; var type = dywhere.GetType(); diff --git a/FreeSql/Internal/Model/TableInfo.cs b/FreeSql/Internal/Model/TableInfo.cs index 3352d77b..fc8195cd 100644 --- a/FreeSql/Internal/Model/TableInfo.cs +++ b/FreeSql/Internal/Model/TableInfo.cs @@ -5,6 +5,8 @@ using System.Reflection; namespace FreeSql.Internal.Model { class TableInfo { public Type Type { get; set; } + public Type TypeLazy { get; set; } + public MethodInfo TypeLazySetOrm { get; set; } public Dictionary Properties { get; set; } = new Dictionary(StringComparer.CurrentCultureIgnoreCase); public Dictionary Columns { get; set; } = new Dictionary(StringComparer.CurrentCultureIgnoreCase); public Dictionary ColumnsByCs { get; set; } = new Dictionary(StringComparer.CurrentCultureIgnoreCase); diff --git a/FreeSql/Internal/UtilsExpressionTree.cs b/FreeSql/Internal/UtilsExpressionTree.cs index f158dc79..6377c12c 100644 --- a/FreeSql/Internal/UtilsExpressionTree.cs +++ b/FreeSql/Internal/UtilsExpressionTree.cs @@ -10,23 +10,25 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; using System.Diagnostics; +using System.IO; using System.Linq; using System.Linq.Expressions; using System.Net; using System.Net.NetworkInformation; using System.Reflection; +using System.Text; using System.Text.RegularExpressions; using System.Threading; namespace FreeSql.Internal { class Utils { - static ConcurrentDictionary _cacheGetTableByEntity = new ConcurrentDictionary(); + static ConcurrentDictionary> _cacheGetTableByEntity = new ConcurrentDictionary>(); internal static TableInfo GetTableByEntity(Type entity, CommonUtils common) { if (entity.FullName.StartsWith("<>f__AnonymousType")) return null; - return _cacheGetTableByEntity.GetOrAdd($"{common.DbName}-{entity.FullName}", key => { //区分数据库类型缓存 + return _cacheGetTableByEntity.GetOrAdd(common.DbName, k1 => new ConcurrentDictionary()).GetOrAdd(entity, k2 => { //区分数据库类型缓存 if (common.CodeFirst.GetDbInfo(entity) != null) return null; - + var tbattr = entity.GetCustomAttributes(typeof(TableAttribute), false).LastOrDefault() as TableAttribute; var trytb = new TableInfo(); trytb.Type = entity; @@ -39,11 +41,20 @@ namespace FreeSql.Internal { trytb.DbOldName = trytb.DbOldName?.ToLower(); } trytb.SelectFilter = tbattr?.SelectFilter; + var virtualProps = new List<(PropertyInfo, bool, bool)>(); foreach (var p in trytb.Properties.Values) { var tp = common.CodeFirst.GetDbInfo(p.PropertyType); //if (tp == null) continue; var colattr = p.GetCustomAttributes(typeof(ColumnAttribute), false).LastOrDefault() as ColumnAttribute; - if (tp == null && colattr == null) continue; + if (tp == null && colattr == null) { + if (common.CodeFirst.IsLazyLoading) { + var getIsVirtual = trytb.Type.GetMethod($"get_{p.Name}")?.IsVirtual; + var setIsVirtual = trytb.Type.GetMethod($"set_{p.Name}")?.IsVirtual; + if (getIsVirtual == true || setIsVirtual == true) + virtualProps.Add((p, getIsVirtual == true, setIsVirtual == true)); + } + continue; + } if (colattr == null) colattr = new ColumnAttribute { Name = p.Name, @@ -93,7 +104,66 @@ namespace FreeSql.Internal { foreach (var col in trytb.Primarys) col.Attribute.IsPrimary = true; } - _cacheGetTableByEntity.TryAdd(entity.FullName, trytb); + + if (common.CodeFirst.IsLazyLoading && virtualProps.Any()) { + //virtual 属性延时加载,生态产生新的重写类 + if (trytb.Type.IsNotPublic) throw new Exception("【延时加载】功能发生错误,实体类必须声明为 public"); + + var overrieds = 0; + var cscode = new StringBuilder(); + cscode.AppendLine("using System;") + .AppendLine("using FreeSql.DataAnnotations;") + .AppendLine("using System.Collections.Generic;") + .AppendLine("using System.Linq;") + .AppendLine("") + .Append("public class FreeSqlOverrideLazyEntity").Append(trytb.Type.Name).Append(" : ").Append(trytb.Type.FullName.Replace("+", ".")).AppendLine(" {") + .AppendLine(" public IFreeSql __fsql_orm__ { get; set; }\r\n"); + foreach(var vp in virtualProps) { + TableInfo pktb = null; + if (vp.Item1.PropertyType == trytb.Type) pktb = trytb; + else pktb = GetTableByEntity(vp.Item1.PropertyType, common); + if (pktb == null || pktb.Primarys.Any() == false) { + //continue; + throw new Exception($"【延时加载】功能发生错误,导航属性 {trytb.Type.FullName}.{vp.Item1.Name} 类型不正确,或者实体类型 {vp.Item1.PropertyType.FullName} 缺少主键标识"); + } + + var lmbdWhere = new StringBuilder(); + var vpcols = new ColumnInfo[pktb.Primarys.Length]; + for (var a = 0; a < pktb.Primarys.Length; a++) { + if (trytb.ColumnsByCs.TryGetValue($"{vp.Item1.Name}{pktb.Primarys[a].CsName}", out var trycol) == false && //骆峰命名 + trytb.ColumnsByCs.TryGetValue($"{vp.Item1.Name}_{pktb.Primarys[a].CsName}", out trycol) == false //下划线命名 + ) { + pktb = null; + throw new Exception($"【延时加载】功能发生错误,导航属性 {trytb.Type.FullName}.{vp.Item1.Name} 没有找到对应的字段 {vp.Item1.Name}{pktb.Primarys[a].CsName} 或 {vp.Item1.Name}_{pktb.Primarys[a].CsName}"); + //break; + } + if (a > 0) lmbdWhere.Append(" && "); + lmbdWhere.Append("a.").Append(pktb.Primarys[a].CsName).Append(" == this.").Append(trycol.CsName); + } + if (pktb == null) continue; + + cscode.Append(" public override ").Append(vp.Item1.PropertyType.FullName.Replace("+", ".")).Append(" ").Append(vp.Item1.Name).AppendLine(" {"); + if (vp.Item2) { //get 重写 + cscode.Append(" get => base.").Append(vp.Item1.Name) + .Append(" ?? (base.").Append(vp.Item1.Name) + .Append(" = __fsql_orm__.Select<").Append(vp.Item1.PropertyType.FullName.Replace("+", ".")).Append(">().Where(a => ") + .Append(lmbdWhere.ToString()) + .Append(").ToOne()").AppendLine(");"); + } + if (vp.Item3) { //set 重写 + cscode.Append(" set => base.").Append(vp.Item1.Name).AppendLine(" = value;"); + } + cscode.AppendLine(" }"); + ++overrieds; + } + if (overrieds > 0) { + cscode.AppendLine("}"); + var assemly = Generator.TemplateEngin._compiler.Value.CompileCode(cscode.ToString()); + var type = assemly.DefinedTypes.Where(a => a.FullName.EndsWith($"FreeSqlOverrideLazyEntity{trytb.Type.Name}")).FirstOrDefault(); + trytb.TypeLazy = type; + trytb.TypeLazySetOrm = type.GetProperty("__fsql_orm__").GetSetMethod(); + } + } return trytb; }); } diff --git a/FreeSql/MySql/MySqlCodeFirst.cs b/FreeSql/MySql/MySqlCodeFirst.cs index 67efa3e8..24f94de6 100644 --- a/FreeSql/MySql/MySqlCodeFirst.cs +++ b/FreeSql/MySql/MySqlCodeFirst.cs @@ -24,6 +24,7 @@ namespace FreeSql.MySql { public bool IsAutoSyncStructure { get; set; } = true; public bool IsSyncStructureToLower { get; set; } = false; + public bool IsLazyLoading { get; set; } = false; static object _dicCsToDbLock = new object(); static Dictionary _dicCsToDb = new Dictionary() { diff --git a/FreeSql/MySql/MySqlProvider.cs b/FreeSql/MySql/MySqlProvider.cs index 0fcd92b4..b4becf70 100644 --- a/FreeSql/MySql/MySqlProvider.cs +++ b/FreeSql/MySql/MySqlProvider.cs @@ -36,7 +36,7 @@ namespace FreeSql.MySql { this.Ado = new MySqlAdo(this.InternalCommonUtils, this.Cache, log, masterConnectionString, slaveConnectionString); this.DbFirst = new MySqlDbFirst(this, this.InternalCommonUtils, this.InternalCommonExpression); - this.InternalCommonUtils.CodeFirst = this.CodeFirst = new MySqlCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression); + this.CodeFirst = new MySqlCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression); } internal CommonUtils InternalCommonUtils { get; } diff --git a/FreeSql/MySql/MySqlUtils.cs b/FreeSql/MySql/MySqlUtils.cs index df62c478..58180b26 100644 --- a/FreeSql/MySql/MySqlUtils.cs +++ b/FreeSql/MySql/MySqlUtils.cs @@ -8,10 +8,7 @@ using System.Data.Common; namespace FreeSql.MySql { class MySqlUtils : CommonUtils { - IFreeSql _orm; - - public MySqlUtils(IFreeSql orm) { - _orm = orm; + public MySqlUtils(IFreeSql orm) : base(orm) { } internal override DbParameter AppendParamter(List _params, string parameterName, Type type, object value) { diff --git a/FreeSql/Oracle/OracleCodeFirst.cs b/FreeSql/Oracle/OracleCodeFirst.cs index 9a3cfed5..fcc48438 100644 --- a/FreeSql/Oracle/OracleCodeFirst.cs +++ b/FreeSql/Oracle/OracleCodeFirst.cs @@ -24,6 +24,7 @@ namespace FreeSql.Oracle { public bool IsAutoSyncStructure { get; set; } = true; public bool IsSyncStructureToLower { get; set; } = false; + public bool IsLazyLoading { get; set; } = false; static object _dicCsToDbLock = new object(); static Dictionary _dicCsToDb = new Dictionary() { diff --git a/FreeSql/Oracle/OracleProvider.cs b/FreeSql/Oracle/OracleProvider.cs index 669fb1cd..47c14b43 100644 --- a/FreeSql/Oracle/OracleProvider.cs +++ b/FreeSql/Oracle/OracleProvider.cs @@ -35,7 +35,7 @@ namespace FreeSql.Oracle { this.Cache = new CacheProvider(cache, log); this.Ado = new OracleAdo(this.InternalCommonUtils, this.Cache, log, masterConnectionString, slaveConnectionString); - this.InternalCommonUtils.CodeFirst = this.CodeFirst = new OracleCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression); + this.CodeFirst = new OracleCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression); } internal CommonUtils InternalCommonUtils { get; } diff --git a/FreeSql/Oracle/OracleUtils.cs b/FreeSql/Oracle/OracleUtils.cs index 9abd7a9c..476bb45e 100644 --- a/FreeSql/Oracle/OracleUtils.cs +++ b/FreeSql/Oracle/OracleUtils.cs @@ -8,9 +8,7 @@ using System.Data.Common; namespace FreeSql.Oracle { class OracleUtils : CommonUtils { - IFreeSql _orm; - public OracleUtils(IFreeSql orm) { - _orm = orm; + public OracleUtils(IFreeSql orm) : base(orm) { } internal override DbParameter AppendParamter(List _params, string parameterName, Type type, object value) { diff --git a/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs b/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs index 0383fdec..9f8e4ea5 100644 --- a/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs +++ b/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs @@ -29,6 +29,7 @@ namespace FreeSql.PostgreSQL { public bool IsAutoSyncStructure { get; set; } = true; public bool IsSyncStructureToLower { get; set; } = false; + public bool IsLazyLoading { get; set; } = false; static object _dicCsToDbLock = new object(); static Dictionary _dicCsToDb = new Dictionary() { diff --git a/FreeSql/PostgreSQL/PostgreSQLProvider.cs b/FreeSql/PostgreSQL/PostgreSQLProvider.cs index 5da914ea..6e54ff2e 100644 --- a/FreeSql/PostgreSQL/PostgreSQLProvider.cs +++ b/FreeSql/PostgreSQL/PostgreSQLProvider.cs @@ -36,7 +36,7 @@ namespace FreeSql.PostgreSQL { this.Ado = new PostgreSQLAdo(this.InternalCommonUtils, this.Cache, log, masterConnectionString, slaveConnectionString); this.DbFirst = new PostgreSQLDbFirst(this, this.InternalCommonUtils, this.InternalCommonExpression); - this.InternalCommonUtils.CodeFirst = this.CodeFirst = new PostgreSQLCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression); + this.CodeFirst = new PostgreSQLCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression); } internal CommonUtils InternalCommonUtils { get; } diff --git a/FreeSql/PostgreSQL/PostgreSQLUtils.cs b/FreeSql/PostgreSQL/PostgreSQLUtils.cs index 18c55556..b3d2c145 100644 --- a/FreeSql/PostgreSQL/PostgreSQLUtils.cs +++ b/FreeSql/PostgreSQL/PostgreSQLUtils.cs @@ -11,9 +11,7 @@ using System.Net; namespace FreeSql.PostgreSQL { class PostgreSQLUtils : CommonUtils { - IFreeSql _orm; - public PostgreSQLUtils(IFreeSql orm) { - _orm = orm; + public PostgreSQLUtils(IFreeSql orm) : base(orm) { } static Array getParamterArrayValue(Type arrayType, object value, object defaultValue) { diff --git a/FreeSql/SqlServer/SqlServerCodeFirst.cs b/FreeSql/SqlServer/SqlServerCodeFirst.cs index 6f0c11f1..03c325f9 100644 --- a/FreeSql/SqlServer/SqlServerCodeFirst.cs +++ b/FreeSql/SqlServer/SqlServerCodeFirst.cs @@ -23,6 +23,7 @@ namespace FreeSql.SqlServer { public bool IsAutoSyncStructure { get; set; } = true; public bool IsSyncStructureToLower { get; set; } = false; + public bool IsLazyLoading { get; set; } = false; static object _dicCsToDbLock = new object(); static Dictionary _dicCsToDb = new Dictionary() { diff --git a/FreeSql/SqlServer/SqlServerProvider.cs b/FreeSql/SqlServer/SqlServerProvider.cs index f74a2fdc..dfed9862 100644 --- a/FreeSql/SqlServer/SqlServerProvider.cs +++ b/FreeSql/SqlServer/SqlServerProvider.cs @@ -35,7 +35,7 @@ namespace FreeSql.SqlServer { this.Ado = new SqlServerAdo(this.InternalCommonUtils, this.Cache, log, masterConnectionString, slaveConnectionString); this.DbFirst = new SqlServerDbFirst(this, this.InternalCommonUtils, this.InternalCommonExpression); - this.InternalCommonUtils.CodeFirst = this.CodeFirst = new SqlServerCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression); + this.CodeFirst = new SqlServerCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression); } internal CommonUtils InternalCommonUtils { get; } diff --git a/FreeSql/SqlServer/SqlServerUtils.cs b/FreeSql/SqlServer/SqlServerUtils.cs index b68204ef..26a5b17b 100644 --- a/FreeSql/SqlServer/SqlServerUtils.cs +++ b/FreeSql/SqlServer/SqlServerUtils.cs @@ -8,9 +8,7 @@ using System.Data.SqlClient; namespace FreeSql.SqlServer { class SqlServerUtils : CommonUtils { - IFreeSql _orm; - public SqlServerUtils(IFreeSql orm) { - _orm = orm; + public SqlServerUtils(IFreeSql orm) : base(orm) { } internal override DbParameter AppendParamter(List _params, string parameterName, Type type, object value) { diff --git a/FreeSql/Sqlite/SqliteCodeFirst.cs b/FreeSql/Sqlite/SqliteCodeFirst.cs index 540f1f9e..339bed5f 100644 --- a/FreeSql/Sqlite/SqliteCodeFirst.cs +++ b/FreeSql/Sqlite/SqliteCodeFirst.cs @@ -23,6 +23,7 @@ namespace FreeSql.Sqlite { public bool IsAutoSyncStructure { get; set; } = true; public bool IsSyncStructureToLower { get; set; } = false; + public bool IsLazyLoading { get; set; } = false; static object _dicCsToDbLock = new object(); static Dictionary _dicCsToDb = new Dictionary() { diff --git a/FreeSql/Sqlite/SqliteProvider.cs b/FreeSql/Sqlite/SqliteProvider.cs index ddb516bd..a269102f 100644 --- a/FreeSql/Sqlite/SqliteProvider.cs +++ b/FreeSql/Sqlite/SqliteProvider.cs @@ -35,7 +35,7 @@ namespace FreeSql.Sqlite { this.Cache = new CacheProvider(cache, log); this.Ado = new SqliteAdo(this.InternalCommonUtils, this.Cache, log, masterConnectionString, slaveConnectionString); - this.InternalCommonUtils.CodeFirst = this.CodeFirst = new SqliteCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression); + this.CodeFirst = new SqliteCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression); } internal CommonUtils InternalCommonUtils { get; } diff --git a/FreeSql/Sqlite/SqliteUtils.cs b/FreeSql/Sqlite/SqliteUtils.cs index a9ff66d9..6644d130 100644 --- a/FreeSql/Sqlite/SqliteUtils.cs +++ b/FreeSql/Sqlite/SqliteUtils.cs @@ -9,9 +9,7 @@ using System.Data.SQLite; namespace FreeSql.Sqlite { class SqliteUtils : CommonUtils { - IFreeSql _orm; - public SqliteUtils(IFreeSql orm) { - _orm = orm; + public SqliteUtils(IFreeSql orm) : base(orm) { } internal override DbParameter AppendParamter(List _params, string parameterName, Type type, object value) { diff --git a/readme.md b/readme.md index f4c69248..37f8bb32 100644 --- a/readme.md +++ b/readme.md @@ -31,6 +31,8 @@ IFreeSql fsql = new FreeSql.FreeSqlBuilder() .UseAutoSyncStructure(true) //自动同步实体结构到数据库 .UseSyncStructureToLower(true) //转小写同步结构 + + .UseLazyLoading(true) //延时加载导航属性对象,导航属性需要声明 virtual .Build(); ```