【问题标题】:Adding dynamic attributes to a model向模型添加动态属性
【发布时间】:2013-04-11 12:05:44
【问题描述】:

我无法解决这个问题,还没有找到正确的搜索键:

我想要几个categoriesitems,其中所有items 都有特定的attributes。那些attributes(文本字段、下拉菜单或复选框)应该添加到category,我想为每个item编辑和保存那些attributes

我正在使用 MVC 4 和代码优先 EF5。我该如何实现?

我的第一个方法是几个类,如 TextDropdown,它们继承自抽象 Attribute 类和 Category 类,如下所示:

public class Category
{
    [Key]
    public int CategoryId { get; set; }

    public string Name { get; set; }
    public string Description { get; set; }

    public virtual ICollection<Item> Items { get; set; }
    public virtual ICollection<Attribute> Attributes { get; set; } 
}

但后来我不知道继续。我是在正确的道路上还是完全错误的?谁能给我一些我可以搜索的提示?

编辑

最终,我正在尝试构建一个高保真设备列表。扬声器具有与放大器不同的属性,而扬声器具有与录音机不同的属性。我想统一查看每个设备的详细信息,并通过额外的免费文本区域为该类别预定义特定属性。扬声器 XYZ 是我的 item,扬声器是我的 category,dB 是 attribute

【问题讨论】:

  • 只有我一个人不明白你的问题吗?我不太明白什么是属性或什么是项目或彼此之间以及与类别之间的关系是什么
  • @Fendy:我编辑了我的问题,这样会更清楚吗?
  • 我已经尝试回答了。希望我的理解足够好。

标签: asp.net-mvc entity-framework design-patterns


【解决方案1】:

好的,所以这个问题基本上是关于数据设计的。

首先,我假设规则是:

  1. 一个项目有一个类别
  2. 一个类别有很多属性
  3. 一个项目有许多与类别相关的属性

对于第一条规则,它在您的设计中已经足够好了。 (简化示例)

public class Category{
  public IEnumerable<Item> Items{get;set;}
}
public class Item{
  public Category Category{get;set;}
}

够清楚了。

对于第 2 条规则,我认为您应该创建一个 CategoryAttribute 类。它持有一对多类别和属性之间的关系。基本上,CategoryAttribute 是主属性,而子属性是 ItemAttribute。

public class Category{
  public IEnumerable<CategoryAttribute> CategoryAttributes{get;set;}
}
public class CategoryAttribute{
  public Category Category{get;set;}
  public string CategoryName{get;set;}
  public string DefaultValue{get;set;} // maybe a default value for specific 
                                       // attribute, but it's up to you

  public IEnumerable<ItemAttribute> ItemAttributes{get;set;}
}

IEnumerable&lt;ItemAttribute&gt; 是类别属性和项目属性之间的一对多关系。

对于规则 3,规则 2 中描述的 ItemAttribute 将表示每个项目所拥有的属性。

public class Item{
  public IEnumerable<ItemAttribute> ItemAttributes{get;set;}
}
public class ItemAttribute{
  public Item Item {get;set;} // it owned by one attribute
  public CategoryAttribute{get;set;} // it owned by one category attribute
}

我不太确定如何首先在代码中表示关系或主键和外键。希望如果需要(如果可以的话),我可以增强我的答案。但希望我对每个对象的关系和类设计的说明。

【讨论】:

    【解决方案2】:

    我认为这样的事情可能对你有用......

    public class Category
    {
        public int CategoryId { get; set; }
    
        public string Name { get; set; }
        public string Description { get; set; }
    
        public virtual ICollection<Item> Items { get; set; }
        public virtual ICollection<Attribute> Attributes { get; set; }
    }
    
    public class Item
    {
        public int ItemId { get; set; }
    
        public string Name { get; set; }
        public string Description { get; set; }
    
        public int CategoryId { get; set; }
        public Category Category { get; set; }
        public virtual ICollection<ItemAttribute> ItemAttributes { get; set; }
    }
    
    public class Attribute
    {
        public int AttributeId { get; set; }
    
        public string Name { get; set; }
        public string Description { get; set; }
    
        public virtual ICollection<Category> Categories { get; set; }
        public virtual ICollection<ItemAttribute> ItemAttributes { get; set; }
    }
    
    public class ItemAttribute
    {
        public int ItemId { get; set; }
        public int AttributeId { get; set; }
    
        public Item Item { get; set; }
        public Attribute Attribute { get; set; }
    
        public string Value { get; set; }
        public int ValueInt{ get; set; }
        // etc. 
    }
    
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<ItemAttribute>()
            .HasKey(x => new { x.ItemId, x.AttributeId });
        modelBuilder.Entity<ItemAttribute>()
            .HasRequired(x => x.Item)
            .WithMany(x => x.ItemAttributes)
            .HasForeignKey(x => x.ItemId)
            .WillCascadeOnDelete(false);
        modelBuilder.Entity<ItemAttribute>()
            .HasRequired(x => x.Attribute)
            .WithMany(x => x.ItemAttributes)
            .HasForeignKey(x => x.AttributeId)
            .WillCascadeOnDelete(false);
        // AttributeCategories is created for you - but you can do the same as ^ above to customize
        // just change 'ICollection<Category> Categories' to collection of 'ItemAttribute'
    }
    
    // use it like e.g.
    var item = new Item { Name = "ItemTest", };
    var attribute = new Attribute { Name = "attributeTest", };
    item.ItemAttributes = new List<ItemAttribute> 
    {
        new ItemAttribute { Item = item, Attribute = attribute, Value = "test", },
    };
    var category = new Category
    {
        Name = "cat1",
        Items = new[]
        {
            item,
            new Item{ Name = "Item1", },
            new Item{ Name = "Item2", },
            new Item{ Name = "Item3", },
            new Item{ Name = "Item4", },
            new Item{ Name = "Item5", },
        },
        Attributes = new[]
        {
            attribute,
            new Attribute{ Name = "att1", },
            new Attribute{ Name = "att2", },
        }
    };
    db.Categories.Add(category);
    db.SaveChanges();
    var categories = db.Categories.ToList();
    

    ItemAttribute用于连接和存储values

    您将需要根据您的要求进一步调整。

    【讨论】:

    • 谢谢,到目前为止一切正常。现在我不仅想要字符串属性,还想要下拉菜单和复选框。我怎么能扩展到那个?
    • 是的,你还有一些工作要做——我希望这是为你指明正确的方向。那里没有直接的答案。您可以添加多个字段,如 I hinted - 并在 ItemAttribute 中包含 text、int、bool - 并根据 type 属性使用任何您需要的字段。您也可以尝试继承 - 即使 ItemAttr 成为基础并使用几个 attr 类型进行扩展 - 但这必然会导致一些问题。虽然可以工作(但我没有时间尝试)。我建议保持简单 - 为每个“原始类型”添加多个“可为空”字段,你应该没问题。
    • 如果您确实尝试继承 - 那么我建议将其保留在 TPH 中(例如没有 [Table()] ) - 因为它有更多的工作机会(因为它实际上都在同一张桌子,就像现在一样)。检查我制作的这个详细示例(超出您的需要)。 stackoverflow.com/questions/15885279/…。自己尝试一下 - 并发布你管理的内容 - 我会尝试看看它。
    【解决方案3】:

    我实际上从未使用过代码优先方法,但我可以告诉您如何处理这种情况......对我来说,看起来Item 是主要的,而不是Category。所以你可以有这个结构......

    public class Category
    {
        [Key]
        public int CategoryId { get; set; }
        public string CategoryName { get; set; }
        public string CategoryDescription { get; set; }
        // use attributes here if you want them for Category
        //public Dictionary<string, string> ItemnAttributes { get; set; }
    }
    
    public class MyItem
    {
        [Key]
        public int ItemId { get; set; }
        public string ItemName { get; set; }
        public string ItemDescription { get; set; }
        public Category ItemnCatagory { get; set; }
        public Dictionary<string, string> ItemnAttributes { get; set; }
    }
    

    希望这会有所帮助..

    【讨论】:

    • 但是属性被分配给每个项目,而不是一个类别。为现有类别创建新项目意味着复制同一类别中另一个项目的属性,不是吗?
    • 因为您在第二行中提到“所有项目都有特定的属性。”...但是如果您想将属性与类别相关联,只需将此属性放在“类别”中并从“我的项目”中删除..
    • 嘿,我弄得一团糟...我认为为您的属性使用“Dictionary”就足够了,而不是“List>”...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-27
    • 2015-08-28
    • 2011-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-16
    相关资源
    最近更新 更多