将属性从Excel数据表映射到列表时出现问题

帕沙

知名会员
已加入
2020年4月29日
留言内容
64
编程经验
1-3
,当前未映射值,并显示NULL值

例如在测试数据模型中,我有一个字段paymentOptions,在Excel工作表中,值是KlarnaOptions,但是在要列出的数据表的映射之后-paymentOptions的值显示为NULL

测试数据模型:


Test Data Model:
using ContradoWebsiteAutoFramework.Constants;
using ContradoWebsiteAutoFramework.Model;
using ContradoWebsiteAutoFramework.Model.PaymentOptions;
using Framework.Model.Excel;
using System.Collections.Generic;

namespace ContradoWebSiteAutoFramework.Model.Excel
{
    public partial class TestDataModel
    {
    
        public TestDataModel() {

        
        }
    
    
        [DataNames("TestName")]
        public string TestName { get; set; }

    

        [DataNames("productId")]
        public int productId { get; set; }

        [DataNames("orderId")]
        public int orderId { get; set; }

    
        [DataNames("designMethod")]
        public DesignMethod designMethod { get; set; }

        [DataNames("signedIn")]
        public bool signedIn { get; set; }

        [DataNames("increaseBasketQty")]
        public bool increaseBasketQty { get; set; }

        [DataNames("signedInCMS")]
        public bool signedInCMS { get; set; }

        [DataNames("editable")]
        public bool editable { get; set; }

        [DataNames("paymentOptions")]
        public PaymentOptions paymentOptions { get; set; }

        [DataNames("checkInVoice")]
        public bool checkInVoice { get; set; }

        [DataNames("navigateToDesign")]
        public bool navigateToDesign { get; set; }

        [DataNames("checkOrderAuthorsie")]
        public bool checkOrderAuthorsie { get; set; }

        [DataNames("checkSplitOrder")]
        public bool checkSplitOrder { get; set; }

        [DataNames("SiteId")]
        public string SiteId { get; set; }

        [DataNames("SiteUrl")]
        public string SiteUrl { get; set; }

        [DataNames("CultureCode")]
        public string CultureCode { get; set; }

        [DataNames("SiteGroupId")]
        public string SiteGroupId { get; set; }

        [DataNames("NickName")]
        public string NickName { get; set; }

        [DataNames("byCard")]
        public KlarnaOptions byCard { get; set; }

        [DataNames("payLater")]
        public bool 以后支付 { get; set; }

        [DataNames("sliceIt")]
        public bool sliceIt { get; set; }

        [DataNames("portal")]
        public PaymentPortal portal { get; set; }

        [DataNames("delivery")]
        public DeliveryMethod 交货{get;set;}

    }

}

用于将数据表转换为列表的映射器:
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Framework.Model.Excel
{
    public class DataNamesMapper<TEntity> where TEntity : class, new()
    {
        public TEntity Map(DataRow row)
        {
            TEntity entity = new TEntity();
            return Map(row, entity);
        }

        public TEntity Map(DataRow row, TEntity entity)
        {
            var columnNames = row.Table.Columns.Cast<DataColumn>().Select(x => x.ColumnName).ToList();
            var properties = (typeof(TEntity)).GetProperties()
                                              .Where(x => x.GetCustomAttributes(typeof(DataNamesAttribute), true).Any())
                                              .ToList();
            foreach (var prop in properties)
            {
                PropertyMapHelper.Map(typeof(TEntity), row, prop, entity);
            }

            return entity;
        }

        public IEnumerable<TEntity> Map(DataTable table)
        {
            清单<TEntity> entities = new 清单<TEntity>();
            var columnNames = table.Columns.Cast<DataColumn>().Select(x => x.ColumnName).ToList();
            var properties = (typeof(TEntity)).GetProperties()
                                              .Where(x => x.GetCustomAttributes(typeof(DataNamesAttribute), true).Any())
                                              .ToList();
            foreach (DataRow row in table.Rows)
            {
                TEntity entity = new TEntity();
                foreach (var prop in properties)
                {
                    PropertyMapHelper.Map(typeof(TEntity), row, prop, entity);
                }
                entities.Add(entity);
            }

            return entities;
        }
    }
}

Property Map 救命er:
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Framework.Model.Excel
{
    public static class PropertyMapHelper
    {

        public static void Map(Type type, DataRow row, PropertyInfo prop, object entity)
        {
            清单<string> columnNames = AttributeHelper.GetDataNames(type, prop.Name);

            foreach (var columnName in columnNames)
            {
                if (!String.IsNullOrWhiteSpace(columnName) && row.Table.Columns.Contains(columnName))
                {
                    var propertyValue = row[columnName];
                    if (propertyValue != DBNull.Value)
                    {
                        ParsePrimitive(prop, entity, row[columnName]);
                        break;
                    }
                }
            }
        }

        private static void ParsePrimitive(PropertyInfo prop, object entity, object value)
        {
            if (prop.PropertyType == typeof(string))
            {
                prop.SetValue(entity, value.ToString().Trim(), null);
            }
            else if (prop.PropertyType == typeof(bool) || prop.PropertyType == typeof(bool?))
            {
                if (value == null)
                {
                    prop.SetValue(entity, null, null);
                }
                else
                {
                    prop.SetValue(entity, ParseBoolean(value.ToString()), null);
                }
            }
            else if (prop.PropertyType == typeof(long))
            {
                prop.SetValue(entity, long.Parse(value.ToString()), null);
            }
            else if (prop.PropertyType == typeof(int) || prop.PropertyType == typeof(int?))
            {
                if (value == null)
                {
                    prop.SetValue(entity, null, null);
                }
                else
                {
                    prop.SetValue(entity, int.Parse(value.ToString()), null);
                }
            }
            else if (prop.PropertyType == typeof(decimal))
            {
                prop.SetValue(entity, decimal.Parse(value.ToString()), null);
            }
            else if (prop.PropertyType == typeof(double) || prop.PropertyType == typeof(double?))
            {
                double number;
                bool isValid = double.TryParse(value.ToString(), out number);
                if (isValid)
                {
                    prop.SetValue(entity, double.Parse(value.ToString()), null);
                }
            }
            else if (prop.PropertyType == typeof(DateTime) || prop.PropertyType == typeof(Nullable<DateTime>))
            {
                DateTime date;
                bool isValid = DateTime.TryParse(value.ToString(), out date);
                if (isValid)
                {
                    prop.SetValue(entity, date, null);
                }
                else
                {
                    isValid = DateTime.TryParseExact(value.ToString(), "MMddyyyy", new CultureInfo("en-US"), DateTimeStyles.AssumeLocal, out date);
                    if (isValid)
                    {
                        prop.SetValue(entity, date, null);
                    }
                }
            }
 else if (prop.PropertyType.IsEnum)
            {
                var type = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
                var enumValue = Enum.Parse(type,value.ToString(), true);
                prop.SetValue(entity, enumValue, null);
            }
            else if (prop.PropertyType == typeof(Guid))
            {
                Guid guid;
                bool isValid = Guid.TryParse(value.ToString(), out guid);
                if (isValid)
                {
                    prop.SetValue(entity, guid, null);
                }
                else
                {
                    isValid = Guid.TryParseExact(value.ToString(), "B", out guid);
                    if (isValid)
                    {
                        prop.SetValue(entity, guid, null);
                    }
                }


            }
         
        }

        public static bool ParseBoolean(object value)
        {
            if (value == null || value == DBNull.Value) return false;

            switch (value.ToString().ToLowerInvariant())
            {
                case "1":
                case "y":
                case "yes":
                case "true":
                    return true;

                case "0":
                case "n":
                case "no":
                case "false":
                default:
                    return false;
            }
        }
    }
}

我想将列映射到的自定义属性类型:
using ContradoWebsiteAutoFramework.Entities;

namespace ContradoWebsiteAutoFramework.Model.PaymentOptions
{
    public class PaymentOptions
    {
        public PaymentPortal portal;
        public DeliveryMethod 交货 = DeliveryMethod.Billing;

        public PaymentOptions()
        {
        }
        public PaymentOptions(Site site)
        {

        }
    }
}
DataName属性类别:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Framework.Model.Excel
{
    [AttributeUsage(AttributeTargets.Property)]
    public class DataNamesAttribute : Attribute
    {
        protected 清单<string> _valueNames { get; set; }

        public 清单<string> ValueNames
        {
            get
            {
                return _valueNames;
            }
            set
            {
                _valueNames = value;
            }
        }

        public DataNamesAttribute()
        {
            _valueNames = new 清单<string>();
        }

        public DataNamesAttribute(params string[] valueNames)
        {
            _valueNames = valueNames.ToList();
        }
    }
}
自定义类被进一步继承:
namespace ContradoWebsiteAutoFramework.Model.PaymentOptions
{
    public class KlarnaOptions : PaymentOptions
    {
        //default - don't use card payment by deffault
        public bool byCard = false;
        public bool 以后支付 = false;
        public bool sliceIt = false;
        public KlarnaOptions()
        {
            portal = PaymentPortal.Klarna;
        }
    }
}
 
Last edited:

帕沙

知名会员
已加入
2020年4月29日
留言内容
64
编程经验
1-3
这取决于您是否要像博客作者一样编写通用的解决方案,还是要针对特定​​问题编写特定的解决方案。针对您的特定问题编写代码将涉及较少的总体代码,并且更易于理解,但是它将与您的类紧密结合。

Basically, you would have a ParseObjects() method whose job is to instantiate 和 fill in object properties. That means your ParsePrimitive() should return whether it parsed a primitive value or not, 和 that you should have something that checks that so that it will call your ParseObjects() instead.

Within te ParseObjects() you would again inspect the type of the property to determine if it's one of your known class types. You then would instantiate the appropriate class, 和 assign that instance to the property of the parent object. The next you would start reading values out of your row 和 setting them on properties of that instance (as opposed to the ParsePrimitive() which was setting the the values directly to the property of the parent object). If you are smart, you can just call ParsePrimitive()和pass in this new instance instance instead of the parent object. You may need to do this recursively if this new instance also has non-primitive properties.

For the generic solution, you would need to change the code for the DataNamesAttribute to also take an optional class type. This is for the case when the property type is base or abstract type, but you want instantiate a specific type further down the hierarchy. Then in the ParseObjects() class instead of checking for your well known class types, you would have to instantiate either the type specified in the attribute, or if not specified in the attribute, the type of the property. Then the rest is the same as the previous paragraph regarding setting parent object properties 和 child object properties.

我想针对目前遇到的一些困难的情况编写一些特定问题的代码
 

帕沙

知名会员
已加入
2020年4月29日
留言内容
64
编程经验
1-3
我专门指的是Automapper:

它没有专门与EntityFramework绑定。无论何时您需要将一种对象映射到另一种对象。
我想知道我是否应该继续使用Auto Mapper,在这里我将为产品选项和klarnaloptions类创建DTO,并使用DTO进行映射?

这样可以解决问题吗?
 

帕沙

知名会员
已加入
2020年4月29日
留言内容
64
编程经验
1-3
@跳伞 -抱歉,我想再询问一次,但是我无法将对象解析为所需的类型,请您帮忙吗?


尝试解析PaymentOptions:
else if (prop.PropertyType == typeof(PaymentOptions))
            {
                prop.SetValue(entity, prop.Name, null);
            }

但它不起作用,我无法理解如何获取值映射
 

帕沙

知名会员
已加入
2020年4月29日
留言内容
64
编程经验
1-3
当前我们正在访问和初始化如下

之前我们曾经访问和分配如下值

赋值

C#:
public class WorkflowParameters

    {
        public Site _site = default(Site);
        public PaymentOptions paymentOptions = default(PaymentOptions);
    }
var param = new WorkflowParameters()

            {
paymentOptions = new KlarnaOptions()

                {

                    交货 = DeliveryMethod.Billing,

                    以后支付 = true

                }

            };


但是我无法A.解析对象和B.解析后如何添加"delivery" 和 "payLater"PaymentOptions中的选项

作为这个领域的新手,这真的越来越难
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,926
地点
英国
编程经验
10+
问题就在这里。 。 。

您从另一个博客或页面上获取了代码,却在不了解其工作原理或理解情况的情况下使用了它。您是来这里寻求帮助的,并将其链接到以下文档集:
我专门指的是Automapper:

它没有专门与EntityFramework绑定。无论何时您需要将一种对象映射到另一种对象。
现在,您已经回来询问如何使用自动映射器,即使这些文档并不严重缺乏材料。你期望"google" or "search"尽管缺乏一些基本知识,但您在此项目中所做的工作仍在进行中。您正在尝试建立某种类型的付款系统,这可能会导致 haXeD。 多年来,我了解到,如果人们不了解基本知识,就不可能教人们高级编码技能。而且我向自己证明,在您所处的环境中帮助他人是浪费时间。

没有冒犯的意思!我只能告诉您的是,您理解这种工作方式的方法都是错误的,并且我不会浪费自己的时间来向您解释。年轻的时候,我也很早就使用论坛,而我发现最能帮助我的是一直将我链接到MSDN和其他文档的人们。阅读是您的学习方式,而要求提供帮助则是您如何对这种语言要求的学习曲线一无所知。

我建议您阅读以下内容: 入门指南— AutoMapper文档
此外,我建议使用MSDN,并采用它们在文档入门部分提供的速成课程。您可以在我的签名中找到一个链接。我通过告诉你总结一下;您将无法使用当前的方法来完成此项目。
 

帕沙

知名会员
已加入
2020年4月29日
留言内容
64
编程经验
1-3
问题就在这里。 。 。

您从另一个博客或页面上获取了代码,却在不了解其工作原理或理解情况的情况下使用了它。您是来这里寻求帮助的,并将其链接到以下文档集:

现在,您已经回来询问如何使用自动映射器,即使这些文档并不严重缺乏材料。你期望"google" or "search"尽管缺乏一些基本知识,但您在此项目中所做的工作仍在进行中。您正在尝试建立某种类型的付款系统,这可能会导致 haXeD。 多年来,我了解到,如果人们不了解基本知识,就不可能教人们高级编码技能。而且我向自己证明,在您所处的环境中帮助他人是浪费时间。

没有冒犯的意思!我只能告诉您的是,您理解这种工作方式的方法都是错误的,并且我不会浪费自己的时间来向您解释。年轻的时候,我也很早就使用论坛,而我发现最能帮助我的是一直将我链接到MSDN和其他文档的人们。阅读是您的学习方式,而要求提供帮助则是您如何对这种语言要求的学习曲线一无所知。

我建议您阅读以下内容: 入门指南— AutoMapper文档
此外,我建议使用MSDN,并采用它们在文档入门部分提供的速成课程。您可以在我的签名中找到一个链接。我通过告诉你总结一下;您将无法使用当前的方法来完成此项目。
当然,我会仔细阅读Automapper文档并尝试理解它
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
@跳伞 -抱歉,我想再询问一次,但是我无法将对象解析为所需的类型,请您帮忙吗?


尝试解析PaymentOptions:
else if (prop.PropertyType == typeof(PaymentOptions))
            {
                prop.SetValue(entity, prop.Name, null);
            }

但它不起作用,我无法理解如何获取值映射
考虑到您将属性的值设置为null,为什么对它不起作用感到惊讶。尝试实例化一个Klarna付款对象并将属性值设置为对新实例的引用。
 
最佳 底部