public static TypeAdapterBuilder <TSource> EntityFromContext <TSource>(this TypeAdapterBuilder <TSource> builder, DbContext context)
        {
            const string dbKey = "Mapster.EFCore.db";

            return(builder
                   .AddParameters(dbKey, context)
                   .ForkConfig(config =>
            {
                foreach (var entityType in context.Model.GetEntityTypes())
                {
                    var type = entityType.ClrType;
                    var keys = entityType.FindPrimaryKey().Properties.Select(p => p.Name).ToArray();
                    var settings = config.When((srcType, destType, mapType) => destType == type);
                    settings.Settings.ConstructUsingFactory = arg =>
                    {
                        //var db = (DbContext)MapContext.Current.Parameters[DB_KEY];
                        //var set = db.Set<T>();
                        //return set.Find(src.id) ?? new T();
                        var src = Expression.Parameter(arg.SourceType);
                        var dest = arg.MapType == MapType.MapToTarget
                                ? Expression.Parameter(arg.DestinationType)
                                : null;
                        var db = Expression.Variable(typeof(DbContext), "db");
                        var set = Expression.Variable(typeof(DbSet <>).MakeGenericType(arg.DestinationType), "set");

                        var current = typeof(MapContext).GetProperty(nameof(MapContext.Current), BindingFlags.Static | BindingFlags.Public);
                        var indexer = typeof(Dictionary <string, object>).GetProperties().First(item => item.GetIndexParameters().Length > 0);
                        var dbAssign = Expression.Assign(
                            db,
                            Expression.Convert(
                                Expression.Property(
                                    Expression.Property(
                                        Expression.Property(null, current),
                                        nameof(MapContext.Parameters)),
                                    indexer,
                                    Expression.Constant(dbKey)),
                                typeof(DbContext)));

                        var setMethod = (from method in typeof(DbContext).GetMethods()
                                         where method.Name == nameof(DbContext.Set) &&
                                         method.IsGenericMethod
                                         select method).First().MakeGenericMethod(arg.DestinationType);
                        var setAssign = Expression.Assign(set, Expression.Call(db, setMethod));

                        var getters = keys.Select(key => arg.DestinationType.GetProperty(key))
                                      .Select(prop => new PropertyModel(prop))
                                      .Select(model => arg.Settings.ValueAccessingStrategies
                                              .Select(s => s(src, model, arg))
                                              .FirstOrDefault(exp => exp != null))
                                      .Where(exp => exp != null)
                                      .Select(exp => Expression.Convert(exp, typeof(object)))
                                      .ToArray();
                        if (getters.Length != keys.Length)
                        {
                            throw new InvalidOperationException($"Cannot get key for sourceType={arg.SourceType.Name}, destinationType={arg.DestinationType.Name}");
                        }
                        Expression find = Expression.Call(set, nameof(DbContext.Find), null,
                                                          Expression.NewArrayInit(typeof(object), getters));
                        if (arg.MapType == MapType.MapToTarget)
                        {
                            find = Expression.Coalesce(find, dest);
                        }
                        var ret = Expression.Coalesce(
                            find,
                            Expression.New(arg.DestinationType));
                        return Expression.Lambda(
                            Expression.Block(new[] { db, set }, dbAssign, setAssign, ret),
                            arg.MapType == MapType.MapToTarget ? new[] { src, dest } : new[] { src });
                    };
                }
            }, context.GetType().FullName));
        }
Esempio n. 2
0
        public static TypeAdapterBuilder <TSource> CreateEntityFromContext <TSource>(this TypeAdapterBuilder <TSource> builder, IObjectContextAdapter context)
        {
            const string DB_KEY = "Mapster.EF6.db";

            return(builder
                   .AddParameters(DB_KEY, context)
                   .ForkConfig(config =>
            {
                var oc = context.ObjectContext;
                var entities = oc.MetadataWorkspace.GetItems <EntityType>(DataSpace.CSpace);
                foreach (var entity in entities)
                {
                    var type = (Type)entity.MetadataProperties.First(prop => prop.Name.EndsWith("ClrType")).Value;
                    var keys = entity.KeyMembers.Select(member => member.Name).ToArray();
                    var settings = config.When((srcType, destType, mapType) => destType == type);
                    settings.Settings.ConstructUsingFactory = arg =>
                    {
                        //var db = (DbContext)MapContext.Current.Parameters[DB_KEY];
                        //var set = db.Set<T>();
                        //return set.Find(src.id) ?? new T();
                        var src = Expression.Parameter(arg.SourceType);
                        var db = Expression.Variable(typeof(DbContext), "db");
                        var set = Expression.Variable(typeof(DbSet <>).MakeGenericType(arg.DestinationType), "set");

                        var current = typeof(MapContext).GetProperty(nameof(MapContext.Current), BindingFlags.Static | BindingFlags.Public);
                        var indexer = typeof(Dictionary <string, object>).GetProperties().First(item => item.GetIndexParameters().Length > 0);
                        var dbAssign = Expression.Assign(
                            db,
                            Expression.Convert(
                                Expression.Property(
                                    Expression.Property(
                                        Expression.Property(null, current),
                                        nameof(MapContext.Parameters)),
                                    indexer,
                                    Expression.Constant(DB_KEY)),
                                typeof(DbContext)));

                        var setMethod = (from method in typeof(DbContext).GetMethods()
                                         where method.Name == nameof(DbContext.Set) &&
                                         method.IsGenericMethod
                                         select method).First().MakeGenericMethod(arg.DestinationType);
                        var setAssign = Expression.Assign(set, Expression.Call(db, setMethod));

                        var getters = keys.Select(key => arg.DestinationType.GetProperty(key))
                                      .Select(prop => new PropertyModel(prop))
                                      .Select(model => arg.Settings.ValueAccessingStrategies
                                              .Select(s => s(src, model, arg))
                                              .FirstOrDefault(exp => exp != null))
                                      .Where(exp => exp != null)
                                      .Select(exp => Expression.Convert(exp, typeof(object)))
                                      .ToArray();
                        if (getters.Length != keys.Length)
                        {
                            throw new InvalidOperationException($"Cannot get key for sourceType={arg.SourceType.Name}, destinationType={arg.DestinationType.Name}");
                        }
                        var ret = Expression.Coalesce(
                            Expression.Call(set, nameof(DbSet.Find), null, Expression.NewArrayInit(typeof(object), getters)),
                            Expression.New(arg.DestinationType));
                        return Expression.Lambda(
                            Expression.Block(new[] { db, set }, dbAssign, setAssign, ret),
                            src);
                    };
                }
            }, context.GetType().FullName));
        }