0

例如,我想在此重载上动态调用 ProjectTo:

public static IQueryable ProjectTo(this IQueryable source, params Expression<Func<TDestination, object>>[] membersToExpand);

像这样

Expression.Call(typeof(AutoMapper.QueryableExtensions.Extensions), "ProjectTo", new[] { DtoType },'What goes here as arguments???')

这是我要调用的重载

public static MethodCallExpression Call(Type type, string methodName, Type[] typeArguments, params Expression[] arguments);

基于此链接: https ://github.com/AutoMapper/AutoMapper/issues/2234#event-1175181678

更新

当我有这样的参数时

IEnumerable<Expression> membersToExpand = new Expression<Func<TDto, object>>[] { };

并将其传递给这样的函数:

Expression.Call(typeof(Extensions), "ProjectTo", new[] { typeof(TDto) }, body, Expression.Constant(membersToExpand));

但是,当membersToExpand参数为null时,它会抛出异常 No generic method 'ProjectTo' on type 'AutoMapper.QueryableExtensions.Extensions' 与提供的类型参数和参数兼容。如果方法是非泛型的,则不应提供类型参数

所以让我澄清一下问题:

'membersToExpand' 必须不为空(好吧,我知道),当它不为空时,'Expression.Call' 可以找到合适的重载并且它会成功但问题是当'membersToExpand' 为空时,我必须创建默认的“membersToExpand”,我必须动态创建它,我不能像这样创建它

Expression.Constant(null, typeof(Expression<Func<TDto, object>>[]))

如何动态创建:

typeof(Expression<Func<TDto, object>>[]

当我只知道'typeof(TDto)'时?

要重现问题只需复制并粘贴,然后运行:

   class Program
{
    static void Main(string[] args)
    {
        Mapper.Initialize(cfg =>
        {
            cfg.CreateMap<UserGroupDto, UserGroup>();
            cfg.CreateMap<UserGroup, UserGroupDto>()
                .ForMember(dest => dest.UserGroupDetails, conf =>
                {
                    conf.MapFrom(ent => ent.UserGroupDetails);
                    conf.ExplicitExpansion();
                });

            cfg.CreateMap<UserGroupDetailDto, UserGroupDetail>();

            cfg.CreateMap<UserGroupDetail, UserGroupDetailDto>()
                .ForMember(dto => dto.UserGroupName, conf => conf.MapFrom(ent => ent.UserGroup.Title));
        });

        //  Someone Wants To Call WITH Members To Expand
        Start(new Expression<Func<UserGroupDto, object>>[] { e => e.UserGroupDetails }); 

        Console.WriteLine("===============================================");

        //  Someone Wants To Call WITHOUT Members To Expand (It's a pain to pass an empty 'new Expression<Func<UserGroupDto, object>>[] { }' so it's better to create the default, dynamically when it's null )
        Start(new Expression<Func<UserGroupDto, object>>[] { });

        //  Someone Wants To Call WITHOUT Members To Expand and pass it null and it will THROW Exception
        // Start(null); 

        Console.ReadLine();
    }

    static void Start(IEnumerable<Expression> membersToExpand)
    {
        using (var db = new MyDbContext())
        {
            IEnumerable projected = CallProjectToDynamically(db.UserGroups.AsQueryable(), typeof(UserGroupDto), membersToExpand);

            foreach (var item in projected.OfType<UserGroupDto>())
            {
                Console.WriteLine(" UserGroupID =>   " + item.ID);
                Console.WriteLine(" UserGroupTitle =>   " + item.Title);

                if (item.UserGroupDetails != null)
                    item.UserGroupDetails.ToList().ForEach(d =>
                    {
                        Console.WriteLine(" UserGroupDetailID =>   " + d.ID);
                        Console.WriteLine(" UserGroupDetailTitle =>   " + d.Title);
                        Console.WriteLine(" UserGroupDetailUserGroupName =>   " + d.UserGroupName);
                    });

            }

        }
    }

    static IQueryable CallProjectToDynamically<T>(IQueryable<T> source, Type dtoType, IEnumerable<Expression> membersToExpand)
    {
        // What i want is this:
        // if(membersToExpand == null)
        // Create The default dynamically For 'params Expression<Func<TDestination, object>>[] membersToExpand'


        var param = Expression.Parameter(typeof(IQueryable<T>), "data");

        var body = Expression.Call(typeof(Extensions), "ProjectTo", new[] { dtoType }, param, Expression.Constant(membersToExpand));

        return (Expression.Lambda<Func<IQueryable<T>, IQueryable>>(body, param).Compile())(source);
    }
}
public partial class MyDbContext : DbContext
{
    public MyDbContext()
        : base("name=MyDbContext")
    {
        Database.SetInitializer(new MyDbContextDBInitializer());
    }

    public virtual DbSet<UserGroup> UserGroups { get; set; }
    public virtual DbSet<UserGroupDetail> UserGroupMembers { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<UserGroup>()
            .HasMany(e => e.UserGroupDetails)
            .WithRequired(e => e.UserGroup)
            .HasForeignKey(e => e.UserGroupID);

    }


}
public class MyDbContextDBInitializer : DropCreateDatabaseAlways<MyDbContext>
{
    protected override void Seed(MyDbContext context)
    {
        IList<UserGroup> defaultStandards = new List<UserGroup>
        {
            new UserGroup() {  Title = "First UserGroup", UserGroupDetails = new [] { new UserGroupDetail { Title = "UGD for First UserGroup" } } },
            new UserGroup() {  Title = "Second UserGroup", UserGroupDetails = new [] { new UserGroupDetail { Title = "UGD for Second UserGroup" } } },
            new UserGroup() {  Title = "Third UserGroup", UserGroupDetails = new [] { new UserGroupDetail { Title = "UGD for Third UserGroup" } } }
        };

        foreach (UserGroup std in defaultStandards)
            context.UserGroups.Add(std);

        base.Seed(context);
    }
}
public partial class UserGroup
{
    public UserGroup()
    {
        UserGroupDetails = new HashSet<UserGroupDetail>();
    }

    public long ID { get; set; }
    public string Title { get; set; }

    public virtual ICollection<UserGroupDetail> UserGroupDetails { get; set; }

}
public partial class UserGroupDetail
{
    public long ID { get; set; }
    public long UserGroupID { get; set; }
    public string Title { get; set; }

    public virtual UserGroup UserGroup { get; set; }

}
public partial class UserGroupDto
{
    public long ID { get; set; }
    public string Title { get; set; }

    public IEnumerable<UserGroupDetailDto> UserGroupDetails { get; set; }

}
public partial class UserGroupDetailDto
{
    public long ID { get; set; }
    public string Title { get; set; }
    public long UserGroupID { get; set; }
    public string UserGroupName { get; set; }

}

真挚地。

4

2 回答 2

0
var call = Expression.Call(typeof(AutoMapper.QueryableExtensions.Extensions), "ProjectTo", new[] { typeof(Bar) },
                            Expression.Constant(source), Expression.Constant(null, typeof(Expression<Func<Bar, object>>[])));

但我认为你在浪费时间。在最新版本中,您甚至不允许传递 null。

于 2017-08-07T11:07:52.450 回答
0

我通过将代码包装到通用方法中来解决这个问题。当我使用时,ProjectTo<T>我不需要传递第二个参数。这是我的助手,它接受字段的类型和列表并返回DataTableDB2DbContext

public static class DTODataHelper
{
    public static DataTable GetDataOfType(DB2 db, string[] fields, Type type)
    {
        var method = typeof(DTODataHelper).GetMethod("GetData").MakeGenericMethod(type);

        var result = method.Invoke(null, new object[] { db, fields }) as DataTable;

        return result;
    }

    public static DataTable GetData<T>(DB2 db, string[] fields)
    {
        var dtoType = typeof(T);

        var source = Mapper.Configuration.GetAllTypeMaps().Where(i => i.DestinationType == dtoType).Select(i => i.SourceType).FirstOrDefault();

        if (source == null)
            throw new HMException("Не найден источник данных");

        var dbSet = db.Set(source);

        var querable = dbSet.AsQueryable();

        var list = dbSet.ProjectTo<T>().ToList();

        return GetDataTable(list, fields);
    }

    public static DataTable GetDataTable<T>(IEnumerable<T> varlist, string[] fields)
    {
        DataTable dtReturn = new DataTable();
        PropertyInfo[] oProps = null;

        var hasColumnFilter = fields != null && fields.Length > 0;

        if (varlist == null) return dtReturn;

        foreach (T rec in varlist)
        {
            if (oProps == null)
            {
                oProps = rec.GetType().GetProperties();

                var excludedProperties = new List<PropertyInfo>();

                foreach (PropertyInfo pi in oProps)
                {
                    if (hasColumnFilter && !fields.Contains(pi.Name))
                    {
                        excludedProperties.Add(pi);
                        continue;
                    }

                    Type colType = pi.PropertyType;

                    if (colType.IsGenericType && colType.GetGenericTypeDefinition() == typeof(Nullable<>))
                    {
                        colType = colType.GetGenericArguments()[0];
                    }

                    var piName = pi.GetCustomAttributes().OfType<DisplayNameAttribute>().FirstOrDefault()?.DisplayName ?? pi.Name;

                    dtReturn.Columns.Add(new DataColumn(piName, colType));
                }

                if (excludedProperties.Count > 0)
                {
                    oProps = oProps.Except(excludedProperties).ToArray();
                }
            }

            DataRow dr = dtReturn.NewRow();
            foreach (PropertyInfo pi in oProps)
            {
                var piName = pi.GetCustomAttributes().OfType<DisplayNameAttribute>().FirstOrDefault()?.DisplayName ?? pi.Name;

                dr[piName] = pi.GetValue(rec, null) == null ? DBNull.Value : pi.GetValue(rec, null);
            }

            dtReturn.Rows.Add(dr);
        }
        return dtReturn;
    }
}
于 2019-10-05T08:01:33.293 回答