第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問(wèn)題,去搜搜看,總會(huì)有你想問(wèn)的

使用嵌套屬性動(dòng)態(tài)生成 LINQ 選擇

使用嵌套屬性動(dòng)態(tài)生成 LINQ 選擇

C#
浮云間 2021-11-21 10:19:44
目前我們有一個(gè)包可以從字符串中的字段動(dòng)態(tài)生成 linq 選擇。它適用于平面屬性,但它不是設(shè)計(jì)用于嵌套字段,如 someObj.NestedObj.SomeField。我們當(dāng)前的代碼在服務(wù)方法中的工作方式如下:_context.Shipments    .Where(s => s.Id == request.Id) // it does not matter just an example    .Select(request.Fields)    .ToPage(request); // ToPage extension comes from a nuget package請(qǐng)求對(duì)象的參數(shù)“字段”只是一個(gè)以逗號(hào)分隔的字符串,包括 Shipment 對(duì)象的屬性。我對(duì) Shipment 進(jìn)行了一些重構(gòu),我將一些字段分組到一個(gè)名為 Address 的新類中,并將其添加到 Shipment 中,如下所示:// before refactoringclass Shipment {    // other fields...    public string SenderAddress;    public string SenderCityName;    public string SenderCityId;    public string RecipientAddress;    public string CityName;    public string CityId;}// after refactoringclass Shipment {   // other fields...   public Address Sender;   public Address Recipient;}class Address {    public string AddressText;    public string CityName;    public string CityId;}為了當(dāng)前的數(shù)據(jù)庫(kù)映射,我添加了相應(yīng)的映射:public class ShipmentMap : DataEntityTypeConfiguration<Shipment>    {        public ShipmentMap()        {            ToTable("Shipments");            // other property mappings            Property(s => s.Recipient.AddressText).HasMaxLength(1100).HasColumnName("RecipientAddress");            Property(s => s.Recipient.CityName).HasMaxLength(100).HasColumnName("CityName");            Property(s => s.Recipient.CityId).IsOptional().HasColumnName("CityId");            Property(s => s.Sender.AddressText).HasMaxLength(1100).HasColumnName("SenderAddress");            Property(s => s.Sender.CityName).HasMaxLength(100).HasColumnName("SenderCityName");            Property(s => s.Sender.CityId).IsOptional().HasColumnName("SenderCityId");        }    }DataEntityTypeConfiguration 來(lái)自 nuget 包:  public abstract class DataEntityTypeConfiguration<T> : EntityTypeConfiguration<T> where T : class  {    protected virtual void PostInitialize();  }所以,我的問(wèn)題是 select(fields) 在 fields = "Recipient.CityId" 時(shí)不起作用。如何動(dòng)態(tài)生成用于選擇嵌套字段的 linq?
查看完整描述

3 回答

?
拉風(fēng)的咖菲貓

TA貢獻(xiàn)1995條經(jīng)驗(yàn) 獲得超2個(gè)贊

很高興您找到了解決您的特定問(wèn)題的方法。


這是一個(gè)更通用的解決方案,一旦原始屬性名稱和類型匹配(例如Entity->Dto等),以及多級(jí)嵌套,它就會(huì)處理不同的源和目標(biāo)類型:


public static Expression<Func<TSource, TTarget>> BuildSelector<TSource, TTarget>(string members) =>

    BuildSelector<TSource, TTarget>(members.Split(',').Select(m => m.Trim()));


public static Expression<Func<TSource, TTarget>> BuildSelector<TSource, TTarget>(IEnumerable<string> members)

{

    var parameter = Expression.Parameter(typeof(TSource), "e");

    var body = NewObject(typeof(TTarget), parameter, members.Select(m => m.Split('.')));

    return Expression.Lambda<Func<TSource, TTarget>>(body, parameter);

}


static Expression NewObject(Type targetType, Expression source, IEnumerable<string[]> memberPaths, int depth = 0)

{

    var bindings = new List<MemberBinding>();

    var target = Expression.Constant(null, targetType);

    foreach (var memberGroup in memberPaths.GroupBy(path => path[depth]))

    {

        var memberName = memberGroup.Key;

        var targetMember = Expression.PropertyOrField(target, memberName);

        var sourceMember = Expression.PropertyOrField(source, memberName);

        var childMembers = memberGroup.Where(path => depth + 1 < path.Length);

        var targetValue = !childMembers.Any() ? sourceMember :

            NewObject(targetMember.Type, sourceMember, childMembers, depth + 1);

        bindings.Add(Expression.Bind(targetMember.Member, targetValue));

    }

    return Expression.MemberInit(Expression.New(targetType), bindings);

}

前兩種方法只是公開暴露的高級(jí)助手。實(shí)際工作是通過(guò)私有遞歸NewObject方法完成的。它對(duì)當(dāng)前級(jí)別的屬性進(jìn)行分組,并且對(duì)于每個(gè)分組,要么創(chuàng)建簡(jiǎn)單的分配,就像PropertyN = source.Property1.Property2...PropertyN它是最后一個(gè)級(jí)別一樣,要么遞歸地PropertyN = new TypeN { … }否則。


與您的示例中的表達(dá)式匹配的示例用法:


var test = BuildSelector<Shipment, Shipment>(

    "Recipient.CityName, Sender.CityId, Sender.CityName, ParcelUniqueId");

只需Compile在需要時(shí)調(diào)用Func。


查看完整回答
反對(duì) 回復(fù) 2021-11-21
?
素胚勾勒不出你

TA貢獻(xiàn)1827條經(jīng)驗(yàn) 獲得超9個(gè)贊

最后我找到了解決方案。它為兩級(jí)嵌套屬性(如 Shipment.Sender.CityName)生成正確的 lambda。所以任何需要同樣?xùn)|西的人都可以使用它。


我希望它有幫助。


/* this comes from request

*  request.Fields = "Sender.CityId,Sender.CityName,Recipient.CityName,parcelUniqueId"

*/


// in the service method


var shipmentList = _context.Shipments.

                .OrderByDescending(s => s.Id)

                .Skip((request.Page -1) * request.PageSize)

                .Take(request.PageSize)

                .Select(new SelectLambdaBuilder<Shipment>().CreateNewStatement(request.Fields))

                .ToList();


public class SelectLambdaBuilder<T>

{

    // as a performence consideration I cached already computed type-properties

    private static Dictionary<Type, PropertyInfo[]> _typePropertyInfoMappings = new Dictionary<Type, PropertyInfo[]>();

    private readonly Type _typeOfBaseClass = typeof(T);


    private Dictionary<string, List<string>> GetFieldMapping(string fields)

    {

        var selectedFieldsMap = new Dictionary<string, List<string>>();


        foreach (var s in fields.Split(','))

        {

            var nestedFields = s.Split('.').Select(f => f.Trim()).ToArray();

            var nestedValue = nestedFields.Length > 1 ? nestedFields[1] : null;


            if (selectedFieldsMap.Keys.Any(key => key == nestedFields[0]))

            {

                selectedFieldsMap[nestedFields[0]].Add(nestedValue);

            }

            else

            {

                selectedFieldsMap.Add(nestedFields[0], new List<string> { nestedValue });

            }

        }


        return selectedFieldsMap;

    }


    public Func<T, T> CreateNewStatement(string fields)

    {

        ParameterExpression xParameter = Expression.Parameter(_typeOfBaseClass, "s");

        NewExpression xNew = Expression.New(_typeOfBaseClass);


        var selectFields = GetFieldMapping(fields);


        var shpNestedPropertyBindings = new List<MemberAssignment>();

        foreach (var keyValuePair in selectFields)

        {

            PropertyInfo[] propertyInfos;

            if (!_typePropertyInfoMappings.TryGetValue(_typeOfBaseClass, out propertyInfos))

            {

                var properties = _typeOfBaseClass.GetProperties();

                propertyInfos = properties;

                _typePropertyInfoMappings.Add(_typeOfBaseClass, properties);

            }


            var propertyType = propertyInfos

                .FirstOrDefault(p => p.Name.ToLowerInvariant().Equals(keyValuePair.Key.ToLowerInvariant()))

                .PropertyType;


            if (propertyType.IsClass)

            {

                PropertyInfo objClassPropInfo = _typeOfBaseClass.GetProperty(keyValuePair.Key);

                MemberExpression objNestedMemberExpression = Expression.Property(xParameter, objClassPropInfo);


                NewExpression innerObjNew = Expression.New(propertyType);


                var nestedBindings = keyValuePair.Value.Select(v =>

                {

                    PropertyInfo nestedObjPropInfo = propertyType.GetProperty(v);


                    MemberExpression nestedOrigin2 = Expression.Property(objNestedMemberExpression, nestedObjPropInfo);

                    var binding2 = Expression.Bind(nestedObjPropInfo, nestedOrigin2);


                    return binding2;

                });


                MemberInitExpression nestedInit = Expression.MemberInit(innerObjNew, nestedBindings);

                shpNestedPropertyBindings.Add(Expression.Bind(objClassPropInfo, nestedInit));

            }

            else

            {

                Expression mbr = xParameter;

                mbr = Expression.PropertyOrField(mbr, keyValuePair.Key);


                PropertyInfo mi = _typeOfBaseClass.GetProperty( ((MemberExpression)mbr).Member.Name );


                var xOriginal = Expression.Property(xParameter, mi);


                shpNestedPropertyBindings.Add(Expression.Bind(mi, xOriginal));

            }

        }


        var xInit = Expression.MemberInit(xNew, shpNestedPropertyBindings);

        var lambda = Expression.Lambda<Func<T,T>>( xInit, xParameter );


        return lambda.Compile();

    }

它編譯 lambda 如下:


s => new Shipment {

    Recipient = new Address {

        CityName = s.Recipient.CityName

    },

    Sender = new Address {

        CityId = s.Sender.CityId,

        CityName = s.Sender.CityName

    },

    ParcelUniqueId = s.ParcelUniqueId

}

我分享了 debug 的一些截圖:

http://img1.sycdn.imooc.com//6199b14100017d8a14650825.jpg

http://img1.sycdn.imooc.com//6199b14c0001403114030486.jpg

查看完整回答
反對(duì) 回復(fù) 2021-11-21
?
汪汪一只貓

TA貢獻(xiàn)1898條經(jīng)驗(yàn) 獲得超8個(gè)贊

最后我找到了解決方案。它為兩級(jí)嵌套屬性(如 Shipment.Sender.CityName)生成正確的 lambda。所以任何需要同樣?xùn)|西的人都可以使用它。


我希望它有幫助。


/* this comes from request

*  request.Fields = "Sender.CityId,Sender.CityName,Recipient.CityName,parcelUniqueId"

*/


// in the service method


var shipmentList = _context.Shipments.

                .OrderByDescending(s => s.Id)

                .Skip((request.Page -1) * request.PageSize)

                .Take(request.PageSize)

                .Select(new SelectLambdaBuilder<Shipment>().CreateNewStatement(request.Fields))

                .ToList();


public class SelectLambdaBuilder<T>

{

    // as a performence consideration I cached already computed type-properties

    private static Dictionary<Type, PropertyInfo[]> _typePropertyInfoMappings = new Dictionary<Type, PropertyInfo[]>();

    private readonly Type _typeOfBaseClass = typeof(T);


    private Dictionary<string, List<string>> GetFieldMapping(string fields)

    {

        var selectedFieldsMap = new Dictionary<string, List<string>>();


        foreach (var s in fields.Split(','))

        {

            var nestedFields = s.Split('.').Select(f => f.Trim()).ToArray();

            var nestedValue = nestedFields.Length > 1 ? nestedFields[1] : null;


            if (selectedFieldsMap.Keys.Any(key => key == nestedFields[0]))

            {

                selectedFieldsMap[nestedFields[0]].Add(nestedValue);

            }

            else

            {

                selectedFieldsMap.Add(nestedFields[0], new List<string> { nestedValue });

            }

        }


        return selectedFieldsMap;

    }


    public Func<T, T> CreateNewStatement(string fields)

    {

        ParameterExpression xParameter = Expression.Parameter(_typeOfBaseClass, "s");

        NewExpression xNew = Expression.New(_typeOfBaseClass);


        var selectFields = GetFieldMapping(fields);


        var shpNestedPropertyBindings = new List<MemberAssignment>();

        foreach (var keyValuePair in selectFields)

        {

            PropertyInfo[] propertyInfos;

            if (!_typePropertyInfoMappings.TryGetValue(_typeOfBaseClass, out propertyInfos))

            {

                var properties = _typeOfBaseClass.GetProperties();

                propertyInfos = properties;

                _typePropertyInfoMappings.Add(_typeOfBaseClass, properties);

            }


            var propertyType = propertyInfos

                .FirstOrDefault(p => p.Name.ToLowerInvariant().Equals(keyValuePair.Key.ToLowerInvariant()))

                .PropertyType;


            if (propertyType.IsClass)

            {

                PropertyInfo objClassPropInfo = _typeOfBaseClass.GetProperty(keyValuePair.Key);

                MemberExpression objNestedMemberExpression = Expression.Property(xParameter, objClassPropInfo);


                NewExpression innerObjNew = Expression.New(propertyType);


                var nestedBindings = keyValuePair.Value.Select(v =>

                {

                    PropertyInfo nestedObjPropInfo = propertyType.GetProperty(v);


                    MemberExpression nestedOrigin2 = Expression.Property(objNestedMemberExpression, nestedObjPropInfo);

                    var binding2 = Expression.Bind(nestedObjPropInfo, nestedOrigin2);


                    return binding2;

                });


                MemberInitExpression nestedInit = Expression.MemberInit(innerObjNew, nestedBindings);

                shpNestedPropertyBindings.Add(Expression.Bind(objClassPropInfo, nestedInit));

            }

            else

            {

                Expression mbr = xParameter;

                mbr = Expression.PropertyOrField(mbr, keyValuePair.Key);


                PropertyInfo mi = _typeOfBaseClass.GetProperty( ((MemberExpression)mbr).Member.Name );


                var xOriginal = Expression.Property(xParameter, mi);


                shpNestedPropertyBindings.Add(Expression.Bind(mi, xOriginal));

            }

        }


        var xInit = Expression.MemberInit(xNew, shpNestedPropertyBindings);

        var lambda = Expression.Lambda<Func<T,T>>( xInit, xParameter );


        return lambda.Compile();

    }

它編譯 lambda 如下:


s => new Shipment {

    Recipient = new Address {

        CityName = s.Recipient.CityName

    },

    Sender = new Address {

        CityId = s.Sender.CityId,

        CityName = s.Sender.CityName

    },

    ParcelUniqueId = s.ParcelUniqueId

}

我分享了 debug 的一些截圖:我相信你的問(wèn)題出在這段代碼中:


string[] nestedProps = o.Split('.');

Expression mbr = xParameter;


foreach (var prop in nestedProps)

    mbr = Expression.PropertyOrField(mbr, prop);


// property "Field1"

PropertyInfo mi = typeof( Shipment ).GetProperty( ((MemberExpression)mbr).Member.Name );

該foreach循環(huán)被重復(fù)地將值分配給mbr,然后覆蓋它,這意味著它的最終值將是表達(dá)等效過(guò)去值的nestedProps。假設(shè)輸入字符串是"Recipient.CityId",mbr將是 的表達(dá)式CityId。然后,您嘗試GetProperty在Shipment類型上查找名稱為 的屬性,該屬性CityId當(dāng)然不存在(CityId作為 的屬性Address)。


不過(guò),我不確定要解決什么問(wèn)題,因?yàn)槲也淮_定您最終想要什么。


查看完整回答
反對(duì) 回復(fù) 2021-11-21
  • 3 回答
  • 0 關(guān)注
  • 246 瀏覽

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)