mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 02:32:50 +08:00
virtual lazy 加载现实 OneToOne/ManyToOne/OneToMany
This commit is contained in:
parent
08b1df5d3f
commit
9ec287535e
@ -5,6 +5,7 @@ using System.Linq;
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace FreeSql.Tests.MySql {
|
namespace FreeSql.Tests.MySql {
|
||||||
|
|
||||||
public class MySqlSelectTest {
|
public class MySqlSelectTest {
|
||||||
|
|
||||||
ISelect<Topic> select => g.mysql.Select<Topic>();
|
ISelect<Topic> select => g.mysql.Select<Topic>();
|
||||||
@ -15,18 +16,33 @@ namespace FreeSql.Tests.MySql {
|
|||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public int Clicks { get; set; }
|
public int Clicks { get; set; }
|
||||||
public int TestTypeInfoGuid { get; set; }
|
public int TestTypeInfoGuid { get; set; }
|
||||||
|
public virtual TestTypeInfo TestTypeInfo { get; set; }
|
||||||
|
|
||||||
public int TypeGuid { get; set; }
|
public int TypeGuid { get; set; }
|
||||||
public virtual TestTypeInfo Type { get; set; }
|
public virtual TestTypeInfo Type { get; set; }
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public DateTime CreateTime { get; set; }
|
public DateTime CreateTime { get; set; }
|
||||||
|
|
||||||
|
public virtual TopicFields Fields { get; set; }
|
||||||
|
}
|
||||||
|
public class TopicFields {
|
||||||
|
[Column(IsPrimary = true)]
|
||||||
|
public int TopicId { get; set; }
|
||||||
|
public virtual Topic Topic { get; set; }
|
||||||
}
|
}
|
||||||
public class TestTypeInfo {
|
public class TestTypeInfo {
|
||||||
[Column(IsIdentity = true)]
|
[Column(IsIdentity = true)]
|
||||||
public int Guid { get; set; }
|
public int Guid { get; set; }
|
||||||
|
|
||||||
public int ParentId { get; set; }
|
public int ParentId { get; set; }
|
||||||
public TestTypeParentInfo Parent { get; set; }
|
public virtual TestTypeParentInfo Parent { get; set; }
|
||||||
|
|
||||||
|
public int SelfGuid { get; set; }
|
||||||
|
public virtual TestTypeInfo Self { get; set; }
|
||||||
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public virtual ICollection<Topic> Topics { get; set; }
|
||||||
}
|
}
|
||||||
public class TestTypeParentInfo {
|
public class TestTypeParentInfo {
|
||||||
[Column(IsIdentity = true)]
|
[Column(IsIdentity = true)]
|
||||||
@ -38,6 +54,9 @@ namespace FreeSql.Tests.MySql {
|
|||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Lazy() {
|
public void Lazy() {
|
||||||
|
var ts = g.mysql.Select<TestTypeInfo>(1).ToOne();
|
||||||
|
|
||||||
|
|
||||||
Topic t = g.mysql.Select<Topic>(2).ToOne();
|
Topic t = g.mysql.Select<Topic>(2).ToOne();
|
||||||
Topic tz = g.mysql.Select<Topic>(2).ToOne();
|
Topic tz = g.mysql.Select<Topic>(2).ToOne();
|
||||||
var tzType = tz.Type;
|
var tzType = tz.Type;
|
||||||
|
@ -26,146 +26,263 @@ namespace FreeSql.Internal {
|
|||||||
static ConcurrentDictionary<string, ConcurrentDictionary<Type, TableInfo>> _cacheGetTableByEntity = new ConcurrentDictionary<string, ConcurrentDictionary<Type, TableInfo>>();
|
static ConcurrentDictionary<string, ConcurrentDictionary<Type, TableInfo>> _cacheGetTableByEntity = new ConcurrentDictionary<string, ConcurrentDictionary<Type, TableInfo>>();
|
||||||
internal static TableInfo GetTableByEntity(Type entity, CommonUtils common) {
|
internal static TableInfo GetTableByEntity(Type entity, CommonUtils common) {
|
||||||
if (entity.FullName.StartsWith("<>f__AnonymousType")) return null;
|
if (entity.FullName.StartsWith("<>f__AnonymousType")) return null;
|
||||||
return _cacheGetTableByEntity.GetOrAdd(common.DbName, k1 => new ConcurrentDictionary<Type, TableInfo>()).GetOrAdd(entity, k2 => { //区分数据库类型缓存
|
var tbc = _cacheGetTableByEntity.GetOrAdd(common.DbName, k1 => new ConcurrentDictionary<Type, TableInfo>()); //区分数据库类型缓存
|
||||||
if (common.CodeFirst.GetDbInfo(entity) != null) return null;
|
if (tbc.TryGetValue(entity, out var trytb)) return trytb;
|
||||||
|
if (common.CodeFirst.GetDbInfo(entity) != null) return null;
|
||||||
var tbattr = entity.GetCustomAttributes(typeof(TableAttribute), false).LastOrDefault() as TableAttribute;
|
|
||||||
var trytb = new TableInfo();
|
var tbattr = entity.GetCustomAttributes(typeof(TableAttribute), false).LastOrDefault() as TableAttribute;
|
||||||
trytb.Type = entity;
|
trytb = new TableInfo();
|
||||||
trytb.Properties = entity.GetProperties().ToDictionary(a => a.Name, a => a, StringComparer.CurrentCultureIgnoreCase);
|
trytb.Type = entity;
|
||||||
trytb.CsName = entity.Name;
|
trytb.Properties = entity.GetProperties().ToDictionary(a => a.Name, a => a, StringComparer.CurrentCultureIgnoreCase);
|
||||||
trytb.DbName = (tbattr?.Name ?? entity.Name);
|
trytb.CsName = entity.Name;
|
||||||
trytb.DbOldName = tbattr?.OldName;
|
trytb.DbName = (tbattr?.Name ?? entity.Name);
|
||||||
if (common.CodeFirst.IsSyncStructureToLower) {
|
trytb.DbOldName = tbattr?.OldName;
|
||||||
trytb.DbName = trytb.DbName.ToLower();
|
if (common.CodeFirst.IsSyncStructureToLower) {
|
||||||
trytb.DbOldName = trytb.DbOldName?.ToLower();
|
trytb.DbName = trytb.DbName.ToLower();
|
||||||
|
trytb.DbOldName = trytb.DbOldName?.ToLower();
|
||||||
|
}
|
||||||
|
trytb.SelectFilter = tbattr?.SelectFilter;
|
||||||
|
var propsLazy = 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) {
|
||||||
|
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)
|
||||||
|
propsLazy.Add((p, getIsVirtual == true, setIsVirtual == true));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
trytb.SelectFilter = tbattr?.SelectFilter;
|
if (colattr == null)
|
||||||
var virtualProps = new List<(PropertyInfo, bool, bool)>();
|
colattr = new ColumnAttribute {
|
||||||
foreach (var p in trytb.Properties.Values) {
|
Name = p.Name,
|
||||||
var tp = common.CodeFirst.GetDbInfo(p.PropertyType);
|
DbType = tp.Value.dbtypeFull,
|
||||||
//if (tp == null) continue;
|
IsIdentity = false,
|
||||||
var colattr = p.GetCustomAttributes(typeof(ColumnAttribute), false).LastOrDefault() as ColumnAttribute;
|
IsNullable = tp.Value.isnullable ?? true,
|
||||||
if (tp == null && colattr == null) {
|
IsPrimary = false,
|
||||||
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,
|
|
||||||
DbType = tp.Value.dbtypeFull,
|
|
||||||
IsIdentity = false,
|
|
||||||
IsNullable = tp.Value.isnullable ?? true,
|
|
||||||
IsPrimary = false,
|
|
||||||
};
|
|
||||||
if (string.IsNullOrEmpty(colattr.DbType)) colattr.DbType = tp?.dbtypeFull ?? "varchar(255)";
|
|
||||||
colattr.DbType = colattr.DbType.ToUpper();
|
|
||||||
|
|
||||||
if (tp != null && tp.Value.isnullable == null) colattr.IsNullable = tp.Value.dbtypeFull.Contains("NOT NULL") == false;
|
|
||||||
if (colattr.DbType?.Contains("NOT NULL") == true) colattr.IsNullable = false;
|
|
||||||
if (string.IsNullOrEmpty(colattr.Name)) colattr.Name = p.Name;
|
|
||||||
if (common.CodeFirst.IsSyncStructureToLower) colattr.Name = colattr.Name.ToLower();
|
|
||||||
|
|
||||||
if ((colattr.IsNullable == false || colattr.IsIdentity || colattr.IsPrimary) && colattr.DbType.Contains("NOT NULL") == false) {
|
|
||||||
colattr.IsNullable = false;
|
|
||||||
colattr.DbType += " NOT NULL";
|
|
||||||
}
|
|
||||||
if (colattr.IsNullable == true && colattr.DbType.Contains("NOT NULL")) colattr.DbType = colattr.DbType.Replace("NOT NULL", "");
|
|
||||||
colattr.DbType = Regex.Replace(colattr.DbType, @"\([^\)]+\)", m => {
|
|
||||||
var tmpLt = Regex.Replace(m.Groups[0].Value, @"\s", "");
|
|
||||||
if (tmpLt.Contains("CHAR")) tmpLt = tmpLt.Replace("CHAR", " CHAR");
|
|
||||||
if (tmpLt.Contains("BYTE")) tmpLt = tmpLt.Replace("BYTE", " BYTE");
|
|
||||||
return tmpLt;
|
|
||||||
});
|
|
||||||
colattr.DbDefautValue = trytb.Properties[p.Name].GetValue(Activator.CreateInstance(trytb.Type));
|
|
||||||
if (colattr.DbDefautValue == null) colattr.DbDefautValue = tp?.defaultValue;
|
|
||||||
if (colattr.IsNullable == false && colattr.DbDefautValue == null) {
|
|
||||||
var consturctorType = p.PropertyType.GenericTypeArguments.FirstOrDefault() ?? p.PropertyType;
|
|
||||||
colattr.DbDefautValue = Activator.CreateInstance(consturctorType);
|
|
||||||
}
|
|
||||||
|
|
||||||
var col = new ColumnInfo {
|
|
||||||
Table = trytb,
|
|
||||||
CsName = p.Name,
|
|
||||||
CsType = p.PropertyType,
|
|
||||||
Attribute = colattr
|
|
||||||
};
|
};
|
||||||
trytb.Columns.Add(colattr.Name, col);
|
if (string.IsNullOrEmpty(colattr.DbType)) colattr.DbType = tp?.dbtypeFull ?? "varchar(255)";
|
||||||
trytb.ColumnsByCs.Add(p.Name, col);
|
colattr.DbType = colattr.DbType.ToUpper();
|
||||||
}
|
|
||||||
trytb.Primarys = trytb.Columns.Values.Where(a => a.Attribute.IsPrimary).ToArray();
|
|
||||||
if (trytb.Primarys.Any() == false) {
|
|
||||||
trytb.Primarys = trytb.Columns.Values.Where(a => a.Attribute.IsIdentity).ToArray();
|
|
||||||
foreach (var col in trytb.Primarys)
|
|
||||||
col.Attribute.IsPrimary = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (common.CodeFirst.IsLazyLoading && virtualProps.Any()) {
|
if (tp != null && tp.Value.isnullable == null) colattr.IsNullable = tp.Value.dbtypeFull.Contains("NOT NULL") == false;
|
||||||
//virtual 属性延时加载,生态产生新的重写类
|
if (colattr.DbType?.Contains("NOT NULL") == true) colattr.IsNullable = false;
|
||||||
if (trytb.Type.IsNestedPublic == false) throw new Exception("【延时加载】功能发生错误,实体类必须声明为 public");
|
if (string.IsNullOrEmpty(colattr.Name)) colattr.Name = p.Name;
|
||||||
|
if (common.CodeFirst.IsSyncStructureToLower) colattr.Name = colattr.Name.ToLower();
|
||||||
|
|
||||||
var overrieds = 0;
|
if ((colattr.IsNullable == false || colattr.IsIdentity || colattr.IsPrimary) && colattr.DbType.Contains("NOT NULL") == false) {
|
||||||
var cscode = new StringBuilder();
|
colattr.IsNullable = false;
|
||||||
cscode.AppendLine("using System;")
|
colattr.DbType += " NOT NULL";
|
||||||
.AppendLine("using FreeSql.DataAnnotations;")
|
}
|
||||||
.AppendLine("using System.Collections.Generic;")
|
if (colattr.IsNullable == true && colattr.DbType.Contains("NOT NULL")) colattr.DbType = colattr.DbType.Replace("NOT NULL", "");
|
||||||
.AppendLine("using System.Linq;")
|
colattr.DbType = Regex.Replace(colattr.DbType, @"\([^\)]+\)", m => {
|
||||||
.AppendLine("")
|
var tmpLt = Regex.Replace(m.Groups[0].Value, @"\s", "");
|
||||||
.Append("public class FreeSqlOverrideLazyEntity").Append(trytb.Type.Name).Append(" : ").Append(trytb.Type.FullName.Replace("+", ".")).AppendLine(" {")
|
if (tmpLt.Contains("CHAR")) tmpLt = tmpLt.Replace("CHAR", " CHAR");
|
||||||
.AppendLine(" public IFreeSql __fsql_orm__ { get; set; }\r\n");
|
if (tmpLt.Contains("BYTE")) tmpLt = tmpLt.Replace("BYTE", " BYTE");
|
||||||
foreach(var vp in virtualProps) {
|
return tmpLt;
|
||||||
TableInfo pktb = null;
|
});
|
||||||
if (vp.Item1.PropertyType == trytb.Type) pktb = trytb;
|
colattr.DbDefautValue = trytb.Properties[p.Name].GetValue(Activator.CreateInstance(trytb.Type));
|
||||||
else pktb = GetTableByEntity(vp.Item1.PropertyType, common);
|
if (colattr.DbDefautValue == null) colattr.DbDefautValue = tp?.defaultValue;
|
||||||
if (pktb == null || pktb.Primarys.Any() == false) {
|
if (colattr.IsNullable == false && colattr.DbDefautValue == null) {
|
||||||
|
var consturctorType = p.PropertyType.GenericTypeArguments.FirstOrDefault() ?? p.PropertyType;
|
||||||
|
colattr.DbDefautValue = Activator.CreateInstance(consturctorType);
|
||||||
|
}
|
||||||
|
if (colattr.IsIdentity && new[] {
|
||||||
|
typeof(sbyte), typeof(short), typeof(int), typeof(long),
|
||||||
|
typeof(byte), typeof(ushort), typeof(uint), typeof(ulong),
|
||||||
|
typeof(double), typeof(float), typeof(decimal) }.Contains(p.PropertyType.GenericTypeArguments.FirstOrDefault() ?? p.PropertyType) == false)
|
||||||
|
colattr.IsIdentity = false;
|
||||||
|
|
||||||
|
var col = new ColumnInfo {
|
||||||
|
Table = trytb,
|
||||||
|
CsName = p.Name,
|
||||||
|
CsType = p.PropertyType,
|
||||||
|
Attribute = colattr
|
||||||
|
};
|
||||||
|
trytb.Columns.Add(colattr.Name, col);
|
||||||
|
trytb.ColumnsByCs.Add(p.Name, col);
|
||||||
|
}
|
||||||
|
trytb.Primarys = trytb.Columns.Values.Where(a => a.Attribute.IsPrimary).ToArray();
|
||||||
|
if (trytb.Primarys.Any() == false) {
|
||||||
|
trytb.Primarys = trytb.Columns.Values.Where(a => a.Attribute.IsIdentity).ToArray();
|
||||||
|
foreach (var col in trytb.Primarys)
|
||||||
|
col.Attribute.IsPrimary = true;
|
||||||
|
}
|
||||||
|
tbc.TryAdd(entity, trytb);
|
||||||
|
|
||||||
|
//virtual 属性延时加载,动态产生新的重写类
|
||||||
|
if (common.CodeFirst.IsLazyLoading && propsLazy.Any()) {
|
||||||
|
var trytbTypeName = trytb.Type.IsNested ? $"{trytb.Type.DeclaringType.Namespace}.{trytb.Type.DeclaringType.Name}.{trytb.Type.Name}" : $"{trytb.Type.Namespace}.{trytb.Type.Name}";
|
||||||
|
if (trytb.Type.IsPublic == false && trytb.Type.IsNestedPublic == false) throw new Exception($"【延时加载】实体类型 {trytbTypeName} 必须声明为 public");
|
||||||
|
|
||||||
|
var trytbTypeLazyName = $"FreeSqlLazyEntity__{Regex.Replace(trytbTypeName, @"[^\w\d]", "_")}";
|
||||||
|
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 ").Append(trytbTypeLazyName).Append(" : ").Append(trytbTypeName).AppendLine(" {")
|
||||||
|
.AppendLine(" public IFreeSql __fsql_orm__ { get; set; }\r\n");
|
||||||
|
|
||||||
|
foreach (var vp in propsLazy) {
|
||||||
|
var propTypeName = vp.Item1.PropertyType.IsGenericType ?
|
||||||
|
$"{vp.Item1.PropertyType.Namespace}.{vp.Item1.PropertyType.Name.Remove(vp.Item1.PropertyType.Name.IndexOf('`'))}<{string.Join(", ", vp.Item1.PropertyType.GenericTypeArguments.Select(a => a.IsNested ? $"{a.DeclaringType.Namespace}.{a.DeclaringType.Name}.{a.Name}" : $"{a.Namespace}.{a.Name}"))}>" :
|
||||||
|
(vp.Item1.PropertyType.IsNested ? $"{vp.Item1.PropertyType.DeclaringType.Namespace}.{vp.Item1.PropertyType.DeclaringType.Name}.{vp.Item1.PropertyType.Name}" : $"{vp.Item1.PropertyType.Namespace}.{vp.Item1.PropertyType.Name}");
|
||||||
|
//List 或 ICollection,一对多、多对多
|
||||||
|
var propElementType = vp.Item1.PropertyType.GenericTypeArguments.FirstOrDefault() ?? vp.Item1.PropertyType.GetElementType();
|
||||||
|
if (propElementType != null) {
|
||||||
|
if (Activator.CreateInstance(vp.Item1.PropertyType) is ICollection == false) continue;
|
||||||
|
|
||||||
|
if (trytb.Primarys.Any() == false) {
|
||||||
//continue;
|
//continue;
|
||||||
throw new Exception($"【延时加载】功能发生错误,导航属性 {trytb.Type.FullName}.{vp.Item1.Name} 类型不正确,或者实体类型 {vp.Item1.PropertyType.FullName} 缺少主键标识");
|
throw new Exception($"【延时加载】导航属性 {vp.Item1.Name} 解析错误,实体类型 {trytbTypeName} 缺少主键标识,[Column(IsPrimary = true)]");
|
||||||
}
|
}
|
||||||
|
var tbref = propElementType == trytb.Type ? trytb : GetTableByEntity(propElementType, common); //可能是父子关系
|
||||||
|
if (tbref == null) continue;
|
||||||
|
|
||||||
|
var isManyToMany = propElementType != trytb.Type &&
|
||||||
|
tbref.Properties.Where(z => (z.Value.PropertyType.GenericTypeArguments.FirstOrDefault() == trytb.Type || z.Value.PropertyType.GetElementType() == trytb.Type) &&
|
||||||
|
vp.Item1.Name.EndsWith($"{z.Key}s", StringComparison.CurrentCultureIgnoreCase) &&
|
||||||
|
z.Key.EndsWith($"{trytb.CsName}s", StringComparison.CurrentCultureIgnoreCase) &&
|
||||||
|
Activator.CreateInstance(z.Value.PropertyType) is ICollection).Any();
|
||||||
|
//中间表怎么查询
|
||||||
|
if (isManyToMany) continue;
|
||||||
|
|
||||||
|
var refcols = tbref.Properties.Where(z => z.Value.PropertyType == trytb.Type);
|
||||||
|
var refprop = refcols.Count() == 1 ? refcols.First().Value : null;
|
||||||
var lmbdWhere = new StringBuilder();
|
var lmbdWhere = new StringBuilder();
|
||||||
var vpcols = new ColumnInfo[pktb.Primarys.Length];
|
var vpcols = new ColumnInfo[trytb.Primarys.Length];
|
||||||
for (var a = 0; a < pktb.Primarys.Length; a++) {
|
for (var a = 0; a < trytb.Primarys.Length; a++) {
|
||||||
if (trytb.ColumnsByCs.TryGetValue($"{vp.Item1.Name}{pktb.Primarys[a].CsName}", out var trycol) == false && //骆峰命名
|
var findtrytbPkCsName = trytb.Primarys[a].CsName.TrimStart('_');
|
||||||
trytb.ColumnsByCs.TryGetValue($"{vp.Item1.Name}_{pktb.Primarys[a].CsName}", out trycol) == false //下划线命名
|
if (findtrytbPkCsName.StartsWith(trytb.Type.Name, StringComparison.CurrentCultureIgnoreCase)) findtrytbPkCsName = findtrytbPkCsName.Substring(trytb.Type.Name.Length).TrimStart('_');
|
||||||
|
var findtrytb = vp.Item1.Name;
|
||||||
|
if (findtrytb.EndsWith(tbref.CsName + "s")) findtrytb = findtrytb.Substring(0, findtrytb.Length - tbref.CsName.Length - 1);
|
||||||
|
findtrytb += trytb.CsName;
|
||||||
|
if (tbref.ColumnsByCs.TryGetValue($"{findtrytb}{findtrytbPkCsName}", out var trycol) == false && //骆峰命名
|
||||||
|
tbref.ColumnsByCs.TryGetValue($"{findtrytb}_{findtrytbPkCsName}", out trycol) == false //下划线命名
|
||||||
) {
|
) {
|
||||||
pktb = null;
|
if (refprop != null &&
|
||||||
throw new Exception($"【延时加载】功能发生错误,导航属性 {trytb.Type.FullName}.{vp.Item1.Name} 没有找到对应的字段 {vp.Item1.Name}{pktb.Primarys[a].CsName} 或 {vp.Item1.Name}_{pktb.Primarys[a].CsName}");
|
tbref.ColumnsByCs.TryGetValue($"{refprop.Name}{findtrytbPkCsName}", out trycol) == false && //骆峰命名
|
||||||
//break;
|
tbref.ColumnsByCs.TryGetValue($"{refprop.Name}_{findtrytbPkCsName}", out trycol) == false) //下划线命名
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
if (trycol != null && trycol.CsType != tbref.Primarys[a].CsType)
|
||||||
|
throw new Exception($"【延时加载】导航属性 {trytbTypeName}.{vp.Item1.Name} 解析错误,{trytb.CsName}.{trytb.Primarys[a].CsName} 和 {tbref.CsName}.{trycol.CsName} 类型不一致");
|
||||||
|
if (trycol == null)
|
||||||
|
throw new Exception($"【延时加载】导航属性 {trytbTypeName}.{vp.Item1.Name} 在 {tbref.CsName} 中没有找到对应的字段,如:{findtrytb}{findtrytbPkCsName}、{findtrytb}_{findtrytbPkCsName}、{refprop.Name}{findtrytbPkCsName}、{refprop.Name}_{findtrytbPkCsName}");
|
||||||
}
|
}
|
||||||
if (a > 0) lmbdWhere.Append(" && ");
|
if (a > 0) lmbdWhere.Append(" && ");
|
||||||
lmbdWhere.Append("a.").Append(pktb.Primarys[a].CsName).Append(" == this.").Append(trycol.CsName);
|
lmbdWhere.Append("a.").Append(trycol.CsName).Append(" == this.").Append(trytb.Primarys[a].CsName);
|
||||||
}
|
|
||||||
if (pktb == null) continue;
|
|
||||||
|
|
||||||
cscode.Append(" public override ").Append(vp.Item1.PropertyType.FullName.Replace("+", ".")).Append(" ").Append(vp.Item1.Name).AppendLine(" {");
|
if (refprop == null) {
|
||||||
|
var findtrytbName = trycol.CsName;
|
||||||
|
if (findtrytbName.EndsWith(trytb.Primarys.First().CsName)) {
|
||||||
|
findtrytbName = findtrytbName.Remove(findtrytbName.Length - trytb.Primarys.First().CsName.Length).TrimEnd('_');
|
||||||
|
if (tbref.Properties.TryGetValue(findtrytbName, out refprop) && refprop.PropertyType != trytb.Type)
|
||||||
|
refprop = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cscode.Append(" private bool __lazy__").Append(vp.Item1.Name).AppendLine(" = false;")
|
||||||
|
.Append(" public override ").Append(propTypeName).Append(" ").Append(vp.Item1.Name).AppendLine(" {");
|
||||||
if (vp.Item2) { //get 重写
|
if (vp.Item2) { //get 重写
|
||||||
cscode.Append(" get => base.").Append(vp.Item1.Name)
|
cscode.Append(" get {\r\n")
|
||||||
.Append(" ?? (base.").Append(vp.Item1.Name)
|
.Append(" if (base.").Append(vp.Item1.Name).Append(" == null && __lazy__").Append(vp.Item1.Name).AppendLine(" == false) {")
|
||||||
.Append(" = __fsql_orm__.Select<").Append(vp.Item1.PropertyType.FullName.Replace("+", ".")).Append(">().Where(a => ")
|
.Append(" base.").Append(vp.Item1.Name).Append(" = __fsql_orm__.Select<").Append(propElementType.IsNested ? $"{propElementType.DeclaringType.Namespace}.{propElementType.DeclaringType.Name}.{propElementType.Name}" : $"{propElementType.Namespace}.{propElementType.Name}").Append(">().Where(a => ").Append(lmbdWhere.ToString()).AppendLine(").ToList();");
|
||||||
.Append(lmbdWhere.ToString())
|
if (refprop != null) {
|
||||||
.Append(").ToOne()").AppendLine(");");
|
cscode.Append(" foreach (var loc1 in base.").Append(vp.Item1.Name).AppendLine(")")
|
||||||
|
.Append(" loc1.").Append(refprop.Name).AppendLine(" = this;");
|
||||||
|
}
|
||||||
|
cscode.Append(" __lazy__").Append(vp.Item1.Name).AppendLine(" = true;")
|
||||||
|
.Append(" }\r\n")
|
||||||
|
.Append(" return base.").Append(vp.Item1.Name).AppendLine(";")
|
||||||
|
.Append(" }\r\n");
|
||||||
}
|
}
|
||||||
if (vp.Item3) { //set 重写
|
if (vp.Item3) { //set 重写
|
||||||
cscode.Append(" set => base.").Append(vp.Item1.Name).AppendLine(" = value;");
|
cscode.Append(" set => base.").Append(vp.Item1.Name).AppendLine(" = value;");
|
||||||
}
|
}
|
||||||
cscode.AppendLine(" }");
|
cscode.AppendLine(" }");
|
||||||
++overrieds;
|
|
||||||
}
|
} else { //一对一、多对一
|
||||||
if (overrieds > 0) {
|
var tbref = vp.Item1.PropertyType == trytb.Type ? trytb : GetTableByEntity(vp.Item1.PropertyType, common); //可能是父子关系
|
||||||
cscode.AppendLine("}");
|
if (tbref == null) continue;
|
||||||
var assemly = Generator.TemplateEngin._compiler.Value.CompileCode(cscode.ToString());
|
if (tbref.Primarys.Any() == false) {
|
||||||
var type = assemly.DefinedTypes.Where(a => a.FullName.EndsWith($"FreeSqlOverrideLazyEntity{trytb.Type.Name}")).FirstOrDefault();
|
//continue;
|
||||||
trytb.TypeLazy = type;
|
throw new Exception($"【延时加载】导航属性 {trytbTypeName}.{vp.Item1.Name} 解析错误,实体类型 {propTypeName} 缺少主键标识,[Column(IsPrimary = true)]");
|
||||||
trytb.TypeLazySetOrm = type.GetProperty("__fsql_orm__").GetSetMethod();
|
}
|
||||||
|
var isOnoToOne = vp.Item1.PropertyType != trytb.Type &&
|
||||||
|
tbref.Properties.Where(z => z.Value.PropertyType == trytb.Type).Any() &&
|
||||||
|
tbref.Primarys.Length == trytb.Primarys.Length &&
|
||||||
|
string.Join(",", tbref.Primarys.Select(a => a.CsType.FullName)) == string.Join(",", trytb.Primarys.Select(a => a.CsType.FullName));
|
||||||
|
var lmbdWhere = new StringBuilder();
|
||||||
|
var vpcols = new ColumnInfo[tbref.Primarys.Length];
|
||||||
|
for (var a = 0; a < tbref.Primarys.Length; a++) {
|
||||||
|
var findtbrefPkCsName = tbref.Primarys[a].CsName.TrimStart('_');
|
||||||
|
if (findtbrefPkCsName.StartsWith(tbref.Type.Name, StringComparison.CurrentCultureIgnoreCase)) findtbrefPkCsName = findtbrefPkCsName.Substring(tbref.Type.Name.Length).TrimStart('_');
|
||||||
|
if (trytb.ColumnsByCs.TryGetValue($"{vp.Item1.Name}{findtbrefPkCsName}", out var trycol) == false && //骆峰命名
|
||||||
|
trytb.ColumnsByCs.TryGetValue($"{vp.Item1.Name}_{findtbrefPkCsName}", out trycol) == false //下划线命名
|
||||||
|
) {
|
||||||
|
//一对一,主键与主键查找
|
||||||
|
if (isOnoToOne) {
|
||||||
|
var trytbpks = trytb.Primarys.Where(z => z.CsType == tbref.Primarys[a].CsType); //一对一,按类型
|
||||||
|
if (trytbpks.Count() == 1) trycol = trytbpks.First();
|
||||||
|
else {
|
||||||
|
trytbpks = trytb.Primarys.Where(z => string.Compare(z.CsName, tbref.Primarys[a].CsName, true) == 0); //一对一,按主键名相同
|
||||||
|
if (trytbpks.Count() == 1) trycol = trytbpks.First();
|
||||||
|
else {
|
||||||
|
trytbpks = trytb.Primarys.Where(z => string.Compare(z.CsName, $"{tbref.CsName}{tbref.Primarys[a].CsName}", true) == 0); //一对一,主键名 = 表+主键名
|
||||||
|
if (trytbpks.Count() == 1) trycol = trytbpks.First();
|
||||||
|
else {
|
||||||
|
trytbpks = trytb.Primarys.Where(z => string.Compare(z.CsName, $"{tbref.CsName}_{tbref.Primarys[a].CsName}", true) == 0); //一对一,主键名 = 表+_主键名
|
||||||
|
if (trytbpks.Count() == 1) trycol = trytbpks.First();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (trycol != null && trycol.CsType != tbref.Primarys[a].CsType)
|
||||||
|
throw new Exception($"【延时加载】导航属性 {trytbTypeName}.{vp.Item1.Name} 解析错误,{trytb.CsName}.{trycol.CsName} 和 {tbref.CsName}.{tbref.Primarys[a].CsName} 类型不一致");
|
||||||
|
if (trycol == null)
|
||||||
|
throw new Exception($"【延时加载】导航属性 {trytbTypeName}.{vp.Item1.Name} 没有找到对应的字段,如:{vp.Item1.Name}{findtbrefPkCsName}、{vp.Item1.Name}_{findtbrefPkCsName}");
|
||||||
|
}
|
||||||
|
if (a > 0) lmbdWhere.Append(" && ");
|
||||||
|
lmbdWhere.Append("a.").Append(tbref.Primarys[a].CsName).Append(" == this.").Append(trycol.CsName);
|
||||||
|
}
|
||||||
|
|
||||||
|
cscode.Append(" private bool __lazy__").Append(vp.Item1.Name).AppendLine(" = false;")
|
||||||
|
.Append(" public override ").Append(propTypeName).Append(" ").Append(vp.Item1.Name).AppendLine(" {");
|
||||||
|
if (vp.Item2) { //get 重写
|
||||||
|
cscode.Append(" get {\r\n")
|
||||||
|
.Append(" if (base.").Append(vp.Item1.Name).Append(" == null && __lazy__").Append(vp.Item1.Name).AppendLine(" == false) {")
|
||||||
|
.Append(" base.").Append(vp.Item1.Name).Append(" = __fsql_orm__.Select<").Append(propTypeName).Append(">().Where(a => ").Append(lmbdWhere.ToString()).AppendLine(").ToOne();")
|
||||||
|
.Append(" __lazy__").Append(vp.Item1.Name).AppendLine(" = true;")
|
||||||
|
.Append(" }\r\n")
|
||||||
|
.Append(" return base.").Append(vp.Item1.Name).AppendLine(";")
|
||||||
|
.Append(" }\r\n");
|
||||||
|
}
|
||||||
|
if (vp.Item3) { //set 重写
|
||||||
|
cscode.Append(" set => base.").Append(vp.Item1.Name).AppendLine(" = value;");
|
||||||
|
}
|
||||||
|
cscode.AppendLine(" }");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
++overrieds;
|
||||||
}
|
}
|
||||||
return trytb;
|
if (overrieds > 0) {
|
||||||
});
|
cscode.AppendLine("}");
|
||||||
|
var assemly = Generator.TemplateEngin._compiler.Value.CompileCode(cscode.ToString());
|
||||||
|
var type = assemly.DefinedTypes.Where(a => a.FullName.EndsWith(trytbTypeLazyName)).FirstOrDefault();
|
||||||
|
trytb.TypeLazy = type;
|
||||||
|
trytb.TypeLazySetOrm = type.GetProperty("__fsql_orm__").GetSetMethod();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tbc.TryGetValue(entity, out var trytb2) ? trytb2 : trytb;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static T[] GetDbParamtersByObject<T>(string sql, object obj, string paramPrefix, Func<string, Type, object, T> constructorParamter) {
|
internal static T[] GetDbParamtersByObject<T>(string sql, object obj, string paramPrefix, Func<string, Type, object, T> constructorParamter) {
|
||||||
|
@ -168,7 +168,9 @@ where a.table_schema in ({0}) and a.table_name in ({1})".FormatMySql(tboldname ?
|
|||||||
}, StringComparer.CurrentCultureIgnoreCase);
|
}, StringComparer.CurrentCultureIgnoreCase);
|
||||||
|
|
||||||
if (istmpatler == false) {
|
if (istmpatler == false) {
|
||||||
|
var existsPrimary = ExecuteScalar(tbname[0], "select 1 from INFORMATION_SCHEMA.KEY_COLUMN_USAGE where table_schema={0} and table_name={1} limit 1".FormatMySql(tbname));
|
||||||
foreach (var tbcol in tb.Columns.Values) {
|
foreach (var tbcol in tb.Columns.Values) {
|
||||||
|
var isIdentityChanged = tbcol.Attribute.IsIdentity && tbcol.Attribute.DbType.IndexOf("AUTO_INCREMENT", StringComparison.CurrentCultureIgnoreCase) == -1;
|
||||||
if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
|
if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
|
||||||
string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol)) {
|
string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol)) {
|
||||||
if ((tbcol.Attribute.DbType.IndexOf(" unsigned", StringComparison.CurrentCultureIgnoreCase) != -1) != tbstructcol.is_unsigned ||
|
if ((tbcol.Attribute.DbType.IndexOf(" unsigned", StringComparison.CurrentCultureIgnoreCase) != -1) != tbstructcol.is_unsigned ||
|
||||||
@ -176,20 +178,20 @@ where a.table_schema in ({0}) and a.table_name in ({1})".FormatMySql(tboldname ?
|
|||||||
tbcol.Attribute.IsNullable != tbstructcol.is_nullable ||
|
tbcol.Attribute.IsNullable != tbstructcol.is_nullable ||
|
||||||
tbcol.Attribute.IsIdentity != tbstructcol.is_identity) {
|
tbcol.Attribute.IsIdentity != tbstructcol.is_identity) {
|
||||||
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" MODIFY ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" ").Append(tbcol.Attribute.DbType);
|
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" MODIFY ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" ").Append(tbcol.Attribute.DbType);
|
||||||
if (tbcol.Attribute.IsIdentity && tbcol.Attribute.DbType.IndexOf("AUTO_INCREMENT", StringComparison.CurrentCultureIgnoreCase) == -1) sbalter.Append(" AUTO_INCREMENT");
|
if (isIdentityChanged) sbalter.Append(" AUTO_INCREMENT").Append(existsPrimary == null ? "" : ", DROP PRIMARY KEY").Append(", ADD PRIMARY KEY(").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(")");
|
||||||
sbalter.Append(";\r\n");
|
sbalter.Append(";\r\n");
|
||||||
}
|
}
|
||||||
if (tbstructcol.column == tbcol.Attribute.OldName) {
|
if (tbstructcol.column == tbcol.Attribute.OldName) {
|
||||||
//修改列名
|
//修改列名
|
||||||
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" CHANGE COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.OldName)).Append(" ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType);
|
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" CHANGE COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.OldName)).Append(" ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType);
|
||||||
if (tbcol.Attribute.IsIdentity && tbcol.Attribute.DbType.IndexOf("AUTO_INCREMENT", StringComparison.CurrentCultureIgnoreCase) == -1) sb.Append(" AUTO_INCREMENT");
|
if (isIdentityChanged) sb.Append(" AUTO_INCREMENT").Append(existsPrimary == null ? "" : ", DROP PRIMARY KEY").Append(", ADD PRIMARY KEY(").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(")");
|
||||||
sbalter.Append(";\r\n");
|
sbalter.Append(";\r\n");
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//添加列
|
//添加列
|
||||||
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType);
|
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType);
|
||||||
if (tbcol.Attribute.IsIdentity && tbcol.Attribute.DbType.IndexOf("AUTO_INCREMENT", StringComparison.CurrentCultureIgnoreCase) == -1) sbalter.Append(" AUTO_INCREMENT");
|
if (isIdentityChanged) sbalter.Append(" AUTO_INCREMENT").Append(existsPrimary == null ? "" : ", DROP PRIMARY KEY").Append(", ADD PRIMARY KEY(").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(")");
|
||||||
sbalter.Append(";\r\n");
|
sbalter.Append(";\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user