动态创建模型

时间:2016-06-21 13:02:42

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

每次传入连接字符串时,是否可以使用实体框架动态创建整个模型(数据库优先)方法?

我尝试了以下内容:

MetaModel model = new MetaModel();
model.RegisterContext(() => new Model1(connectionString),
new ContextConfiguration()
 {
  ScaffoldAllTables = true
 });

但它不断给我一个错误

  

未处理的类型' System.ArgumentException'发生在System.Web.DynamicData.dll

中      

附加信息:上下文类型' DbContext.Model1'不受支持。

更多信息:

我拥有数据库中我无法控制的所有必需表,如果我需要旧表中的任何新表或列,那么db人员会为我运行相应的脚本。

我尝试使用EF创建一个通用DLL,我可以在各种应用6上使用它,包括winformsmvc网络应用。我试图找出我们最好的方法来解决这个问题。

我可以将codefirstdatabasefirst混合在一起吗?

我不会codefirst为我生成我已经拥有的表格吗?

我的每个应用程序都包含1个winforms和1个Web应用程序,并且它们共享数据源,例如。

  

测试1 Windows App&测试1 MVC App = DB 1

     

测试2 Windows App&测试2 MVC App = DB 2

     

测试3 Windows App&测试3 MVC App = DB 3

所以我需要将connectionstring传递给DBContext。我的实体将如何运作?

如果需要更多信息,请告知我们。

3 个答案:

答案 0 :(得分:4)

技术上 您可以在运行时创建实体框架模型,至少可以动态创建程序集并使用代码首先工作的apis和属性,或者通过创建模型所需的xml。 但是 您不需要在运行时创建模型类。

实际上,在运行时创建模型类是没用的,因为您可以在编译时和运行时创建要键入的模型。您可以创建模型,因为您希望将Type1传递给方法或编写类似.Where(x=>x.SomeFiled == SomeValue)的类型查询。

如果您有针对不同客户的不同应用实例

如果您为不同的客户端提供不同的应用程序实例,则无需执行任何特定操作。您的应用程序已经可以使用,只需在webconfigappconfig中为不同的客户使用不同的连接字符串。

如果所有客户都有一个应用程序实例

在这种具有多租户应用程序的情况下,您只需向db上下文构造函数添加一个重载,该重载接受连接字符串作为输入。然后,当您需要创建数据库上下文的实例时,可以使用该重载并根据租户检测策略在连接字符串中注入合适的用户名,密码和数据库名称。

public partial class SampleDbEntities
{
    public SampleDbEntities(string connectionString) : base(connectionString)
    {
    }
}

最好将新的重载放在部分类中。每次更新上下文运行的edmx.tt模板时,都不会触及它。

例如,您可以通过以下方式创建连接字符串和上下文:

var connectionTemplate =
    @"metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;" +
    @"provider=System.Data.SqlClient;" +
    @"provider connection string=""data source={0};" +
    @"initial catalog={1};" +
    @"persist security info=True;" +
    @"user id={2};" +
    @"password={3};" +  
    @"MultipleActiveResultSets=True;App=EntityFramework""";

string connection = string.Format(connectionTemplate, 
    @"(localdb)\v11.0", @"SampleDB1", @"user1" , @"password1");

var db = new SampleDbEntities(connection);

或者您可能需要Windows身份验证,而不是用户ID和密码,请使用@"integrated security=True;" +

您可以根据不同的策略检测不同的租户,包括:

  • 应用程序网址(域名和子域名)
  • 查询字符串或路由值
  • 用户名

您可以为基于租户策略的类创建合适的上下文。

如果数据库中的表发生了变化,我该怎么办?

只需在设计时更新您的edmx模型并重建您的应用程序并重新分发它。如上所述,如果添加到表或新表的字段已添加到数据库中,并且您希望在应用程序db.Tabe1.Where(x=>x.Field1==value1)中编写此类型查询,则需要从数据库更新模型并重建应用程序。在运行时重新生成模型没有意义。

如何提高工作效率?

我知道您的目标是提高工作效率,但在运行时生成模型并不是您想要的。相反,您可以创建一些通用的数据访问层和通用业务逻辑层来提高生产力。例如,如果您有很多需要CRUD操作的实体,则可以创建EntityBusiness<TContext, TModel>类并使用通用void Create(TModel entity)IList<TModel> GetAll(object key)TModel GetByKey(object key)TModel Update(TModel entity)void DeleteByKey(object key)等。这样您只需创建EntityBusiness<SampleDbEntities, Product>的实例或从中继承。该类包含简单CRUD操作的所有行为,您可以通过添加对其他一些有用情况(如验证)的支持来增强它。作为创建通用存储库和工作单元的示例,请在asp.net mvc站点中查看此article

答案 1 :(得分:0)

是的,您可以在运行时指定连接字符串。

是的,如果修改了表,则需要更新C#类。如果使用数据库优先,请更新edmx并保存。如果您使用代码优先,请手动更新C#类。

一个例子。

实体类

public class Table1 {
    // props...
}

A DbContext

public class MyContext: DbContext {
    public MyContext (string connectionString): base(connectionString) { }
    public DbSet<Table1> Table1 { get; set; }
}

...用法

string connectionstring1 = "someConnectionString";  // Put this in the app.config
using (var context = new MyContext(connectionstring1)) {
    var table1sFromDb1 = context.Table1.ToList();
}

string connectionstring2 = "someOtherConnectionString"; // Put this in the app.config
using (var context = new MyContext(connectionstring2)) {
    var table1sFromDb2 = context.Table1.ToList();
}

答案 2 :(得分:0)

如果您有一个应用程序,则应用程序必须使用最少的表和列集(即实体和属性)。
从数据库生成模型是无用的,因为应用程序必须仅使用共享表和列 在你的情况下,一个好的方法可能是使用CodeFirst(在你的情况下,从数据库的CodeFirst)然后禁用模型检查(检查模型,你仍然可以使用单元测试)。