如何从数据库读取动态属性

6

我会尽力以最好的方式解释我的情况。我在我的数据库中有以下表:

Products{ProductId, CategoryId ...}
Categories{CategoryId ...}
CategoryProperties{CategoryPropertyId, CategoryId, Name ...}
PropertyValues{ProductId, CategoryPropertyId, Value ...}

因此,目标是拥有属于某个类别的产品列表,每个类别可以在“PropertyValues”表中具有“n”数量的属性和值。我有一个查询可以根据“categoryId”返回数据,因此我始终可以从数据库中获取不同的结果:

对于CPU类别:

intel i7 | CPU | Model | Socket | L1 Cash | L2 Cahs | etc.

对于HDD类别:
samsung F3 | HDD | Model | Speed | GB | etc.

基于我的查询结果中的类别,我总是可以获得不同的列数和名称。对于数据库访问,我使用简单的ADO.NET调用存储过程返回结果。但是由于查询结果具有动态性质,我不知道读取这些数据的好方法。
我创建了一个“产品”实体,但我很困惑如何真正制作它。我认为可以创建一个“产品”实体,并创建其他实体,这些实体继承“产品”,例如CPU、硬盘、相机、PC机箱、显卡、手机、GPS等。但我认为这很愚蠢,因为我可能会在域中获得200多个实体。
在这种情况下,您会怎么做?如何读取并存储这些动态属性?
更新-一些解决方案
好吧,基于@millimoose的建议使用字典和@Tim Schmelter使用DataTable对象的想法,我得出了一些解决方案。现在......这有效,我读取数据并可以显示它们。但我仍然需要来自比我聪明的人的建议,关于我是否做得好,或者应该更好地处理它,或者我制作了一些混沌代码。所以这是我做的:
public class Product
    {
        public Product()
        {
            this.DynamicProperties = new List<Dictionary<string, string>>();
        }

        public List<Dictionary<string, string>> DynamicProperties { get; set; }

    }
...
List<Product> products = new List<Product>();
...
using (SqlDataAdapter a = new SqlDataAdapter(cmd))
                {
                    DataTable t = new DataTable();
                    a.Fill(t);

                    Product p = null;

                    foreach (DataRow row in t.Rows)
                    {
                        p = new Product();
                        foreach (DataColumn col in t.Columns)
                        {
                            string property = col.ColumnName.ToString();
                            string propertyValue = row[col.ColumnName].ToString();

                            Dictionary<string, string> dictionary = new Dictionary<string, string>();

                            dictionary.Add(property, propertyValue);

                            p.DynamicProperties.Add(dictionary);
                        }

                        products.Add(p);
                    }
                }

1
你有必要在你的模型类中拥有这些属性吗?为什么不只是让Product拥有一个单一的Dictionary<string, object>(或类似的东西)呢? - millimoose
最简单的方法是使用 DataTables。然后您只需要一个 SQL 查询和一个 SqlDataAdapter 来填充表格。 - Tim Schmelter
@millimoose 我一开始想到的是 Dictionary。但我想知道在这种情况下是否有其他不同的解决方案。或者 Dictionary 实际上是唯一或最好的解决方案。 - 1110
1
@1110 看起来你需要一个安全保障。你可以尝试使用 Dictionary,这似乎是显而易见的选择。如果在设计中遇到问题,请回来询问相关问题。 - millimoose
@1110 你也可以看看 Steve Yegge 关于他所称的“属性模式”的文章。免责声明:这篇文章很长,他有时会偏离主题。 - millimoose
millimoose和Tim Schmelter,根据你们的评论,我想出了一些解决方案。你们能检查一下我问题的更新吗? - 1110
2个回答

2

你原本的方法

public class Product
{
    public List<Dictionary<string, string>> DynamicProperties { get; set; }
}

很不错。但我会使用自定义集合,更好地命名以使意图更清晰。


您也可以利用C# 4.0的dynamic特性更加"酷",但我不确定它在您的情况下有什么好处。您可以这样做:

public class Product
{
    public List<dynamic> DynamicProperties { get; set; }
}

...

conn.Open();
using (var reader = cmd.ExecuteReader())
{
    var p = new Products();
    p.DynamicProperties = reader.AsDyamic().ToList();

    //or

    foreach (var item in reader.AsDynamic())
        yield return item;
}

// carry this extension method around
public static IEnumerable<dynamic> AsDynamic(this IDataReader reader)
{
    var names = Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList();
    foreach (IDataRecord record in reader as IEnumerable)
    {
        var expando = new ExpandoObject() as IDictionary<string, object>;
        foreach (var name in names)
            expando[name] = record[name];

        yield return expando;
    }
}

有点相关的问题:如何将数据读取器转换为动态查询结果


1
你有一个产品,一堆类别,每个类别都有一堆属性。
class Product
{
    public int Id { get; set; }
    public Category Category { get; set; }
    public List<ProductProperty> Properties { get; set; }
}

class Category
{
  public int Id { get; set; }
  public string Name { get; set; }
}

class ProductProperty
{
   public  int Id { get; set; }
   public  string Name { get; set; }
   public string Value { get; set; }
}

你可以将产品属性存储在列表/字典中,然后只需向产品添加属性。
Properties.Add(new ProductionProperty() { Name="intel i7"});

或者如果它的名称/值
Properties.Add(new ProductionProperty() { Name="Speed", Value="150MB/s"});

我无法像这样处理它。Properties 属性应该是动态的,因此我无法读取它,因为我不知道属性的名称。 - 1110
它是“动态的”,您只需使用返回的任何内容填充每个ProductProperty。 - Keith Nicholas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接