virtual lazy 加载现实 OneToOne/ManyToOne/OneToMany

This commit is contained in:
28810 2019-01-21 17:58:17 +08:00
parent 08b1df5d3f
commit 9ec287535e
3 changed files with 262 additions and 124 deletions

View File

@ -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;

View File

@ -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) {

View File

@ -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");
} }
} }