1

我对如何从 Excel 读取数据有点困惑。我正在尝试导入 Excel 以更新产品列表,我创建了一个 Excel 模型;我将名称、价格、数量等所有基本属性添加到此模型中。我将阅读所有 Excel 并映射到这个模型中。没关系,那我把这个模型交给EF Core 5保存到SQL Server。

public class ExcelModel
{ 
    public string Name { get; set }
    public int Price { get; set }
    public int Quantity { get; set }
}

我对产品选项有疑问。根据我的数据库模式,我有一张产品表,一张用于选项,一张用于选项值,一张用于 productOptionRelation。

在此处输入图像描述

你能建议另一种解决方案还是按我的方式解决?

我的大学创建了与值相对应的字段。像 option1 和 optionValue1, option2 和 optionValue2 其中很多,因为每个产品可以有很多选项。模型看起来像这样,这里声明了 20 个选项和 20 个值,他们手动映射所有这些

坏模型的图片

对于临时解决方案,我将此选项限制为 5,并创建了一个列表。并将它们全部封装到列表中

public class ExcelOptionViewModel
{
    public string Option { get; set; }
    public string Value { get; set; }
}

这是我的临时模型,我是这样封装的。

 public IList<ExcelOptionViewModel> OptionModels { get; set; } = new List<ExcelOptionViewModel>(); 

 public string Option1
 {
     get { return OptionModels[0].Option; } 
     set
     {
         this.OptionModels.Insert(0, new ExcelOptionViewModel { Option = value });
     }
 }

 public string Option1Value
 {
     get { return OptionModels[0].Value; }
     set { this.OptionModels[0].Value  = value; }
 }

这将是无限的,您应该输入您想要的数量

我有 2 个解决方案我仍在研究一个是,在 excelviewmodel 中创建一个方法,此方法会将所有选项和值添加到列表中,或者我将使用反射,我看起来像底层类型我将所有选项和值这个底层基本类型或其他东西,当属性循环来到这里时,检查类型并将所有 option1、option2、option3 或类似属性的名称分配给List<string> options,对于选项值也是如此。我将使用像 option[0] 和 optionvalue[0] 这样的阅读

Excel 列名必须不同,因为我读取了 excel 并将其转换为数据表。数据表列名必须不同,读入数据表无效

excel导入错误的样本

excel导入真实样本

我基本上使用了 excel 到数据表功能,我不记得了,但可能我在 StackOverflow 中找到了它。另外,我在那里添加了一个功能,如果某些单元格为空,它将丢失。

public List<T> ConvertDataTableToList<T>(DataTable dt)
{
    //datatable clomun names
    var columnNames = dt.Columns.Cast<DataColumn>().Select(c => c.ColumnName.ToLower()).ToList();

    //selection properties equals to columnnames because I dont want loop for all props
    var properties = typeof(T).GetProperties().Where(prp => columnNames.Any(t => t.ToLower() == prp.Name.ToLower()));

    return dt.AsEnumerable().Select(row =>
    {
        var objT = Activator.CreateInstance<T>();
        foreach (var pro in properties)
        {
            try
            {
                if (row[pro.Name] != DBNull.Value)
                    pro.SetValue(objT, row[pro.Name], null);
                else
                    pro.SetValue(objT, null, null);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
        return objT;
    }).ToList();
}

当Option1或Option2来到这里时,我在这里寻找某些东西,它将其列入列表

同样在我的 dt 到模型转换器中,我不想使用 If 但如果某些数据值为 null 它会引发无法从 dbnull 值转换的错误。如果您对此有建议,我想在条件下发布:)

完成后,我会将这个 excelviewmodel 映射到类似这样的产品模型

 foreach (var prop in SideParams.columns)
            {
                var source = row.GetType().GetProperty(prop);

                var destination = product.GetType().GetProperty(prop);

                if (destination != null && source.GetValue(row) != null)
                {
                Type t = Nullable.GetUnderlyingType(destination.PropertyType) ?? destination.PropertyType;

                object safeValue = Convert.ChangeType(source.GetValue(row), t);
                destination.SetValue(product, safeValue);

            }
        }

我在这里看到了一些东西 https://docs.microsoft.com/en-us/dotnet/api/system.reflection.bindingflags?view=net-6.0

它是关于反射模型时的绑定法兰。“指定控制绑定的标志以及通过反射进行搜索成员和类型的方式。” 如果有办法我可以将选项(1-2-3-4-5-6...)重定向到列表选项

4

1 回答 1

0

感谢您帮助我解决了我的问题。如果您需要类似的东西,我的解决方案是;

如您所知,OptionModels 是我之前创建的,AddOptipns 函数是我用于将数据添加到列表的新函数,该函数与 ref 一起使用,否则它必须是静态的,如果我将其变为静态,则选项模型也必须是静态的,所以我无法访问该列表。

 public IList<ExcelOptionViewModel> OptionModels { get; set; } = new List<ExcelOptionViewModel>();
 public void AddOptions(ref String option, ref String value)
     {
        OptionModels.Add(new ExcelOptionViewModel { Option = option.Trim(), Value = value.Trim() });
     }

并且还添加了一些新的部件来转换模型功能,

用反射调用 AddOptions 方法,我从这里得到了一个例子 https://docs.microsoft.com/en-us/dotnet/api/system.reflection.bindingflags?view=net-6.0

我受到了那里的交换示例的启发。

public List<T> ConvertDataTableToList<T>(DataTable dt)
    {
        var columnNames = dt.Columns.Cast<DataColumn>().Select(c => c.ColumnName.ToLower()).ToList();

        //selection properties equals to columnnames because I dont want loop for all props
        var type = typeof(T);
        var properties = type.GetProperties().Where(prp => columnNames.Any(t => t.ToLower() == prp.Name.ToLower())).ToList();

        var productOptions = columnNames.Where(x => x.Contains("option")).ToList() ?? new List<string>();

        return dt.AsEnumerable().Select(row =>
        {
            var objT = Activator.CreateInstance<T>();
            foreach (var pro in properties)
            {
                try
                {
                    if (row[pro.Name] != DBNull.Value)
                        pro.SetValue(objT, row[pro.Name], null);
                    else
                        pro.SetValue(objT, null, null);
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message);
                }
            }

            for (var i = 0; i < productOptions.Count(); i += 2)
            {
                object[] argValues = new object[] { row[productOptions[i]].ToString(), row[productOptions[i + 1]].ToString() };
                String[] argNames = new String[] { "option", "value" } ;
                 
               var method =  type.GetMethod("AddOptions");
                method.Invoke(objT, argValues);
            }

            return objT;
        }).ToList();
    }

这是添加的数据:)

添加数据的示例

于 2021-12-28T13:23:54.903 回答