using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using FreeSql.DataAnnotations; namespace FreeSql.Extensions.EfCoreFluentApi { public class EfCoreTableFluent { IFreeSql _fsql; TableFluent _tf; internal EfCoreTableFluent(IFreeSql fsql, TableFluent tf) { _fsql = fsql; _tf = tf; } public EfCoreTableFluent ToTable(string name) { _tf.Name(name); return this; } public EfCoreTableFluent ToView(string name) { _tf.DisableSyncStructure(true); _tf.Name(name); return this; } public EfCoreColumnFluent Property(Expression> property) => new EfCoreColumnFluent(_tf.Property(property)); public EfCoreColumnFluent Property(string property) => new EfCoreColumnFluent(_tf.Property(property)); public TableFluent Help() => _tf; #region HasKey public EfCoreTableFluent HasKey(Expression> key) { var exp = key?.Body; if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; if (exp == null) throw new ArgumentException("参数错误 key 不能为 null"); switch (exp.NodeType) { case ExpressionType.MemberAccess: _tf.Property((exp as MemberExpression).Member.Name).IsPrimary(true); break; case ExpressionType.New: foreach (var member in (exp as NewExpression).Members) _tf.Property(member.Name).IsPrimary(true); break; } return this; } #endregion #region HasIndex public HasIndexFluent HasIndex(Expression> index) { var exp = index?.Body; if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; if (exp == null) throw new ArgumentException("参数错误 index 不能为 null"); var indexName = $"idx_{Guid.NewGuid().ToString("N").Substring(0, 8)}"; var columns = new List(); switch (exp.NodeType) { case ExpressionType.MemberAccess: columns.Add((exp as MemberExpression).Member.Name); break; case ExpressionType.New: foreach (var member in (exp as NewExpression).Members) columns.Add(member.Name); break; } _tf.Index(indexName, string.Join(", ", columns), false); return new HasIndexFluent(_tf, indexName, columns); } public class HasIndexFluent { TableFluent _modelBuilder; string _indexName; List _columns; bool _isUnique; internal HasIndexFluent(TableFluent modelBuilder, string indexName, List columns) { _modelBuilder = modelBuilder; _indexName = indexName; _columns = columns; } public HasIndexFluent IsUnique() { _isUnique = true; _modelBuilder.Index(_indexName, string.Join(", ", _columns), _isUnique); return this; } public HasIndexFluent HasName(string name) { _modelBuilder.IndexRemove(_indexName); _indexName = name; _modelBuilder.Index(_indexName, string.Join(", ", _columns), _isUnique); return this; } } #endregion #region HasOne public HasOneFluent HasOne(Expression> one) { var exp = one?.Body; if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; if (exp == null) throw new ArgumentException("参数错误 one 不能为 null"); var oneProperty = ""; switch (exp.NodeType) { case ExpressionType.MemberAccess: oneProperty = (exp as MemberExpression).Member.Name; break; } if (string.IsNullOrEmpty(oneProperty)) throw new ArgumentException("参数错误 one"); return new HasOneFluent(_fsql, _tf, oneProperty); } public class HasOneFluent { IFreeSql _fsql; TableFluent _tf; string _selfProperty; string _selfBind; string _withManyProperty; string _withOneProperty; string _withOneBind; internal HasOneFluent(IFreeSql fsql, TableFluent modelBuilder, string oneProperty) { _fsql = fsql; _tf = modelBuilder; _selfProperty = oneProperty; } public HasOneFluent WithMany(Expression> many) { var exp = many?.Body; if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; if (exp == null) throw new ArgumentException("参数错误 many 不能为 null"); switch (exp.NodeType) { case ExpressionType.MemberAccess: _withManyProperty = (exp as MemberExpression).Member.Name; break; } if (string.IsNullOrEmpty(_withManyProperty)) throw new ArgumentException("参数错误 many"); if (string.IsNullOrEmpty(_selfBind) == false) _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withManyProperty, _selfBind)); return this; } public HasOneFluent WithOne(Expression> one, Expression> foreignKey) { var exp = one?.Body; if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; if (exp == null) throw new ArgumentException("参数错误 one 不能为 null"); switch (exp.NodeType) { case ExpressionType.MemberAccess: _withOneProperty = (exp as MemberExpression).Member.Name; break; } if (string.IsNullOrEmpty(_withOneProperty)) throw new ArgumentException("参数错误 one"); exp = foreignKey?.Body; if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; if (exp == null) throw new ArgumentException("参数错误 foreignKey 不能为 null"); switch (exp.NodeType) { case ExpressionType.MemberAccess: _withOneBind = (exp as MemberExpression).Member.Name; _withOneBind = _withOneBind.TrimStart(',', ' '); break; case ExpressionType.New: _withOneBind = ""; foreach (var member in (exp as NewExpression).Members) _withOneBind += ", " + member.Name; _withOneBind = _withOneBind.TrimStart(',', ' '); break; } if (string.IsNullOrEmpty(_withOneBind)) throw new ArgumentException("参数错误 foreignKey"); if (string.IsNullOrEmpty(_selfBind) == false) _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withOneProperty, _withOneBind)); return this; } public HasOneFluent HasForeignKey(Expression> foreignKey) { var exp = foreignKey?.Body; if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; if (exp == null) throw new ArgumentException("参数错误 foreignKey 不能为 null"); switch (exp.NodeType) { case ExpressionType.MemberAccess: _selfBind = (exp as MemberExpression).Member.Name; _selfBind = _selfBind.TrimStart(',', ' '); break; case ExpressionType.New: _selfBind = ""; foreach (var member in (exp as NewExpression).Members) _selfBind += ", " + member.Name; _selfBind = _selfBind.TrimStart(',', ' '); break; } if (string.IsNullOrEmpty(_selfBind)) throw new ArgumentException("参数错误 foreignKey"); _tf.Navigate(_selfProperty, _selfBind); if (string.IsNullOrEmpty(_withManyProperty) == false) _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withManyProperty, _selfBind)); if (string.IsNullOrEmpty(_withOneProperty) == false && string.IsNullOrEmpty(_withOneBind) == false) _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withOneProperty, _withOneBind)); return this; } } #endregion #region HasMany public HasManyFluent HasMany(Expression>> many) { var exp = many?.Body; if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; if (exp == null) throw new ArgumentException("参数错误 many 不能为 null"); var manyProperty = ""; switch (exp.NodeType) { case ExpressionType.MemberAccess: manyProperty = (exp as MemberExpression).Member.Name; break; } if (string.IsNullOrEmpty(manyProperty)) throw new ArgumentException("参数错误 many"); return new HasManyFluent(_fsql, _tf, manyProperty); } public class HasManyFluent { IFreeSql _fsql; TableFluent _tf; string _selfProperty; string _selfBind; string _withOneProperty; string _withManyProperty; internal HasManyFluent(IFreeSql fsql, TableFluent modelBuilder, string manyProperty) { _fsql = fsql; _tf = modelBuilder; _selfProperty = manyProperty; } public void WithMany(Expression>> many, Type middleType) { var exp = many?.Body; if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; if (exp == null) throw new ArgumentException("参数错误 many 不能为 null"); switch (exp.NodeType) { case ExpressionType.MemberAccess: _withManyProperty = (exp as MemberExpression).Member.Name; break; } if (string.IsNullOrEmpty(_withManyProperty)) throw new ArgumentException("参数错误 many"); _tf.Navigate(_selfProperty, null, middleType); _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withManyProperty, null, middleType)); } public HasManyFluent WithOne(Expression> one) { var exp = one?.Body; if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; if (exp == null) throw new ArgumentException("参数错误 one 不能为 null"); switch (exp.NodeType) { case ExpressionType.MemberAccess: _withOneProperty = (exp as MemberExpression).Member.Name; break; } if (string.IsNullOrEmpty(_withOneProperty)) throw new ArgumentException("参数错误 one"); if (string.IsNullOrEmpty(_selfBind) == false) _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withOneProperty, _selfBind)); return this; } public HasManyFluent HasForeignKey(Expression> foreignKey) { var exp = foreignKey?.Body; if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; if (exp == null) throw new ArgumentException("参数错误 foreignKey 不能为 null"); switch (exp.NodeType) { case ExpressionType.MemberAccess: _selfBind = (exp as MemberExpression).Member.Name; _selfBind = _selfBind.TrimStart(',', ' '); break; case ExpressionType.New: _selfBind = ""; foreach (var member in (exp as NewExpression).Members) _selfBind += ", " + member.Name; _selfBind = _selfBind.TrimStart(',', ' '); break; } if (string.IsNullOrEmpty(_selfBind)) throw new ArgumentException("参数错误 foreignKey"); _tf.Navigate(_selfProperty, _selfBind); if (string.IsNullOrEmpty(_withOneProperty) == false) _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withOneProperty, _selfBind)); return this; } } #endregion public EfCoreTableFluent Ignore(Expression> property) { _tf.Property(property).IsIgnore(true); return this; } public EfCoreTableFluent HasData(T data) => HasData(new[] { data }); /// /// 使用 Repository + EnableAddOrUpdateNavigateList + NoneParameter 方式插入种子数据 /// /// /// public EfCoreTableFluent HasData(IEnumerable data) { if (data.Any() == false) return this; var sdCopy = data.Select(a => (object)a).ToList(); var sdCopyLock = new object(); _fsql.Aop.SyncStructureAfter += new EventHandler((s, e) => { object[] sd = null; lock (sdCopyLock) sd = sdCopy?.ToArray(); if (sd == null || sd.Any() == false) return; foreach (var et in e.EntityTypes) { if (et != typeof(T)) continue; if (_fsql.Select().AsType(et).Any()) continue; var repo = _fsql.GetRepository(); repo.DbContextOptions.EnableAddOrUpdateNavigateList = true; repo.DbContextOptions.NoneParameter = true; repo.AsType(et); repo.Insert(sd); lock (sdCopyLock) sdCopy = null; } }); return this; } } }