C#ASP.Net MVC动态对象属性

时间:2015-11-21 18:56:51

标签: c# asp.net-mvc entity-framework dynamic-properties

我正在开展ASP.NET MVC项目,首先使用C#EF代码。

我需要向实体添加动态属性。例如 -

我有一辆汽车作为基础物体。我可以为它添加自定义属性,如引擎功率,长度,颜色等。

属性可以是boolean,int,string或select options(即,当用户输入这些属性的值时,我必须创建复选框,输入或选择html元素。)

属性必须具有自定义验证规则(即必需,仅限数字,范围等)。

你们能给我任何线索或指导如何实现这个目标吗?

谢谢

2 个答案:

答案 0 :(得分:1)

如果您确实拥有动态属性,则无法使用EF6(直接)执行此操作,因为EF6假定为关系数据库。并且关系数据库需要知道期望哪些列。

现在你有两个选择。

选项1: 使用EF 7的非关系数据库。你可以在这里查看https://msdn.microsoft.com/en-us/magazine/dn890367.aspx了解有关EF7的更多细节,但基本上在非关系数据库中你可以存储任何json blob - 所以你的动态属性也是如此

选项2:在对象中使用键值对。并存储这些属性

class KeyValuePair {
   int Id {get; set;}
   string name {get; set;}
   string stringValue {get; set;}

}

class BaseObject {

    int Id {get; set;}
    list<KeyValuePair> dynamicProperties {get; set;}

}

现在你的车可以继承这个基础对象。您仍然需要完成创建KeyValuePair对象的工作。 (如果你想存储字符串,整数等,你可以制作不同的KeyValuePair类型,每种存储类型一个)

如果您使用这样的动态属性,请注意性能。

<强>更新

如果要验证这样的动态对象,则需要实现IValidatableObject

所以你得到了

 class Car: BaseObject, IValidatableObject {
      public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
        /* code to validate your properties here, for example you need at least 1 engine, 4 wheels etc */

        yield return ValidationResult.Success;
    }
 }

答案 1 :(得分:0)

您可以动态地在DB中创建和使用表格,但不是那么简单。

首先,您需要存储有关表的元数据 - 它们的名称,它们具有的属性,这些属性的类型等等。

其次,您需要生成实体来访问这些表,还需要生成EntityTypeConfiguration类,如下所示:

public class Foo
{
    public int Id { get; set; }

    public string Name { get; set; }
}

public class FooTypeConfiguration : EntityTypeConfiguration<Foo>
{
    public FooTypeConfiguration()
    {
        ToTable("Foos");
        HasKey(t => t.Id);
        Property(t => t.Name).HasMaxLength(200)
                             .IsRequired();
    }
}

System.Reflection.Emit的帮助下,您可以在没有中间C#代码的情况下动态生成DLL。或者您可以生成C#代码并使用System.CodeDom.Compiler进行编译(这种方式更简单)。您也可以尝试使用Roslyn编译器(但我没有足够的经验来建议)。

第三,您需要加载已编译的DLL并使用DbContext创建modelBuilder.Configurations.AddFromAssembly(...)

您可以在程序集中找到所需类型并使用它来访问数据:

string typeName = ...;
var type = dynamicLoadedAssembly.GetType(typeName);
var set = dbContext.Set(type); // non-generic DB Set

您可以使用System.Reflectiondynamic输入来处理这些对象。 最后,如果您要生成C#代码,您可以生成某些接口的属性和实现,以通过名称访问这些属性:

public interface IAccessorByName : IReadOnlyDictionary<string, object>
{
    object this[string name] { get; set; }
}

public Foo : IAccessorByName
{
    private static readonly IDictionary<string, Func<Foo, object>> getters = new Dictionary<string, Func<Foo, object>>
    {
        { "Id", (foo) => foo.Id },
        { "Name", (foo) => foo.Name },
    };

    private static readonly IDictionary<string, Action<Foo, object>> setters = new Dictionary<string, Action<Foo, object>>
    {
        { "Id", (foo, value) => { foo.Id = (int)value; } },
        { "Name", (foo, value) => { foo.Name = (string)value; } },
    };

    public int Id { get; set; }

    public string Name { get; set; }

    public object this[string name]
    {
       get { return getters[name](this); }
       set { setters[name](this, value); }
    }
}

使用类似的界面,您可以动态创建,读取,更新和删除对象:

string typeName = "Foo";
var fooType = dynamicLoadedAssembly.GetType(typeName);
var foo = (IAccessorByName)Activator.CreateInstance(fooType);

foo["Id"] = 1;
foo["Name"] = "Jon Skeet";

var fooSet = dbContext.Set(fooType);
fooSet.Add(foo);
dbContext.SaveChanges();