【问题标题】:How to combine many properties into one List<string> property in C#如何在 C# 中将多个属性组合成一个 List<string> 属性
【发布时间】:2021-12-27 12:57:39
【问题描述】:

我对如何从 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 中创建一个方法,此方法会将所有选项和值添加到列表中,或者我将使用反射,我看起来像底层类型,我将所有选项和值这个基础基本类型或其他东西,当属性循环来到这里时,检查类型并将所有选项1,选项2,选项3或类似属性的名称分配给List&lt;string&gt; options,对于选项值也是如此。我将使用 option[0] 和 optionvalue[0] 之类的阅读方式

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();
}

我在这里寻找一些东西,当案子1或option2来到这里时它会将其放入列表

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

全部完成后,我会将这个 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...)重定向到列表选项

【问题讨论】:

  • 如何从 excel 中读取数据 你能。也许没有在excel中有这些数据?与将所有表并排堆叠在一个表格形式中相比,有更好的方法来创建数据库并将数据驱动到其中
  • @CaiusJard 不要那样做......这对 OP 没有任何帮助
  • 实际上有很多表产品是主表,选项,选项值,类别,品牌等。我做了所有,插入更新和删除功能对所有表都完美和优化。但只有我没有完成选项。唯一的方法是从 excel 中获取选项我有另一个想法,但它对我们来说很简单,但对用户来说很难。 excel 上只有一个选项和选项值字段,您将编写您的功能拆分;当我读到这篇文章时,我会将它们拆分并插入到 productoptionrelation 表中。但对用户来说真的很难
  • 对用户最好的是添加 option1 和 optionvalue1 和 option2 optionvalue2 列我已经测试过了。
  • @wiwi 做什么?询问他们是否为自己的背部制作了这根棍子?你有没有看到问题中的那一行,上面写着 你可以建议另一种解决方法,或者只是在我的路上解决。 - 我很想建议 另一种解决方法,我想知道它们与解析这个文件的关系如何。也许它的“我的第三方恐龙供应商给了我这个数据,它来自一个无法更改的 COBOL 程序”。也许是“我设计这个是因为我认为这是个好主意”。谁知道呢?让我们问..

标签: c# asp.net datatable ef-core-5.0 excel-import


【解决方案1】:

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

如您所知,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();
    }

这是添加的数据:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-01-05
    • 1970-01-01
    • 2022-11-11
    • 1970-01-01
    • 2021-09-03
    • 2019-02-16
    • 1970-01-01
    相关资源
    最近更新 更多