0

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

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

我有一辆汽车作为基础对象。我可以为其添加自定义属性,例如发动机功率、长度、颜色等。

属性可以是布尔值、整数、字符串或选择选项(即,当用户为这些属性输入值时,我必须创建复选框、输入或选择 html 元素)。

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

你们能给我任何线索或方向来完成这个吗?

谢谢

4

2 回答 2

2

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

现在你有2个选择。

选项 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;
    }
 }
于 2015-11-21T19:08:37.957 回答
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# 代码并使用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();
于 2015-11-21T19:34:59.143 回答