我的项目中要求在运行时动态添加/删除字段。我已经创建了这个功能但不是EF。我想用EF创建这个功能。任何想法如何做到这一点?
答案 0 :(得分:3)
如果您需要动态数据结构,则必须使用完全不同的体系结构,否则无法使用EF。 EF不是动态更改数据库的工具 - 只看看你如何使用EF。您将静态表映射到静态类定义。如果在运行时更改表,如何更改类(EF中没有dynamic
支持)?
作为备用数据库结构的示例,您可以使用具有多个不同类型的预定义列的数据库,并将新字段映射到新类型。您将在应用程序中添加一层“映射”,它将根据存储在其他位置的某些类型元数据来解释您的数据库内容。这是例如Sharepoint(至少2007)使用的方法,其中您有单独存储的内容类型(数据描述),但所有内容都在一个包含大量列的大表中。
另一个示例是结构,其中您有核心数据的单独表(在所有实体之间共享),用于属性描述的单独表和用于与核心数据相关的属性值的单独表。这个数据库结构有一个名字,但我现在不记得了。
每种动态方法都有其代价。一般来说,你会失去一些强类型作品的部分,你会失去表现。
您的链接工具不适用于更改数据库结构。它只是用于修改映射中的名称,但表结构必须保持不变。
答案 1 :(得分:2)
这是来自Rowan Miller Blog的takne verbatin。
http://romiller.com/2012/03/26/dynamically-building-a-model-with-code-first/。
仍然需要更改,以便从某些配置源或数据库表中的字段读取类的属性。
使用代码优先动态构建模型 发表于2012年3月26日。
我最近就这个主题回复了几封电子邮件,所以感觉好像是时候把它变成博客了。
在这种情况下,构成模型的类集在编译时是未知的,并且是在运行时动态发现的。这种场景的一个例子是WordPress / Orchard /等。允许插入模块的样式网站。这些模块位于单独的程序集中,可能包含表示要在应用程序数据库中保留的数据的类。这些类都被引入用于数据访问的中央Code First模型。
查找类 有许多不同的方法可用于识别要包含在模型中的类。对于此示例,我们使用[Persistent]属性,如下所示:
[AttributeUsage(AttributeTargets.Class)] 公共类PersistentAttribute:Attribute { } 现在我们可以为上下文的OnModelCreating方法添加一些逻辑来扫描程序集并添加具有[Persist]属性的任何类。我们假设可能包含类的程序集都被加载到当前的AppDomain中,当然您可能还有一些其他机制可以提供要检查的程序集列表。
public class MyContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var entityMethod = typeof(DbModelBuilder).GetMethod("Entity");
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
var entityTypes = assembly
.GetTypes()
.Where(t =>
t.GetCustomAttributes(typeof(PersistentAttribute), inherit: true)
.Any());
foreach (var type in entityTypes)
{
entityMethod.MakeGenericMethod(type)
.Invoke(modelBuilder, new object[] { });
}
}
}
}
在此示例中,动态发现整个模型,但您也可以使用modelBuilder注册模型的某些静态部分。
使用EntityConfiguration的替代方案 Code First允许您创建一个派生自EntityTypeConfiguration的类,以封装实体的Fluent API配置。如果您使用这种配置方法,您可以只查找这些配置类并注册它们,而不是找到要注册的实体。请注意,我们正在过滤掉EntityFramework程序集,因为它有一些内部使用的配置类。
public class MyContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var addMethod = typeof(ConfigurationRegistrar)
.GetMethods()
.Single(m =>
m.Name == "Add"
&& m.GetGenericArguments().Any(a => a.Name == "TEntityType"));
foreach (var assembly in AppDomain.CurrentDomain
.GetAssemblies()
.Where(a => a.GetName().Name != "EntityFramework"))
{
var configTypes = assembly
.GetTypes()
.Where(t => t.BaseType != null
&& t.BaseType.IsGenericType
&& t.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
foreach (var type in configTypes)
{
var entityType = type.BaseType.GetGenericArguments().Single();
var entityConfig = assembly.CreateInstance(type.FullName);
addMethod.MakeGenericMethod(entityType)
.Invoke(modelBuilder.Configurations, new object[] { entityConfig });
}
}
}
}
如果型号发生变化怎么办? Code First迁移到救援......您可能无法使用从管理器管理器控制台迁移,因为发现模型的逻辑可能需要您运行完整的应用程序。幸运的是,这些命令只是API上的瘦包装器。以下是在将新类或属性添加到模型时自动更改数据库的一些代码。我最近的博客文章提供了有关从代码调用迁移的更多详细信息。
var config = new DbMigrationsConfiguration<MyContext> { AutomaticMigrationsEnabled = true };
var migrator = new DbMigrator(config);
migrator.Update();
答案 2 :(得分:1)
在运行时添加和删除字段不是一个好主意 数据库结构应该是静态的,因为它应该反映您的类结构,并且您的类结构是静态的,无论您是否需要它。
如果你有一个动态表,你最好实现它,例如,有一个表格,其中包含字段“rowID,field,value”,并以这种方式填写值。
如果确实需要在运行时向表中添加/删除字段,可以创建添加/删除字段的存储过程,然后使用实体框架映射SP。 但是,这可能会导致很多问题,因为实体框架将无法映射/取消映射新的/删除的字段,因此在您尝试访问该表时会崩溃。