Entity Framework Code First 学习日记(4)
因为家里有点事,就耽误了随后的更新。很抱歉让大家等了好几天,我就不再耽误时间了,让我们马上切入正题。
上次日记中我跟大家提前透露了这篇日记将介绍一些与DbContext有关的内容。廖羽同学问了两个问题,他问的问题正好是我这次要讲的,我们怎么配置DbContext的子类访问的数据库的位置。
我相信大家最经常使用的数据库位置的配置方式就是配置文件了,也就是通过App.Config 或Web.Config来配置要访问的数据库。
Entity Framework Code First同样也可以通过配置文件来配置要访问的数据库的位置。
我们可以再配置文件里添加一个连接字符串的配置来定义数据库的位置
<connectionStrings>
<add name="OrderSystemContext" connectionString="Data Source=XXX\SQL2008R2;Initial Catalog=OrderSystem;User Id=XXX;Password=XXX" providerName="System.Data.SqlClient"/>
</connectionStrings>
那么Code First怎么知道使用哪个连接字符串来找到要访问的数据库呢?
默认情况下,Code First会在连接字符串的配置节中寻找与你自定的DbContext的子类同名的连接字符串。例如你自定义的DbContext的子类叫OrderSystemContext, 那么name是OrderSystemContext的连接字符串就是你程序中要访问的数据库的连接字符串。
如果我们想改变数据库连接字符串的名字,而不用改变我们自定义的DbContext子类,我们就可以使用DbContext的另一个构造函数
public OrderSystemContext(string databaseName)
: base(databaseName)
{
}
我们可以将连接字符串的名字作为参数传到DbContext子类的构造函数中,然后我们就可以让我们的DbContext子类和连接字符串的名字脱离关系了.
OrderSystemContext unitOfWork = new OrderSystemContext("OrderSystem");
App.Config
<add name="OrderSystem" connectionString="Data Source=CNTSNWV0CN115\SQL2008R2;Initial Catalog=OrderSystem;User Id=ldsng;Password=welcome" providerName="System.Data.SqlClient"/>
还有一个更简单的方式,如果你想使用固定的连接字符串的名字而不是通过参数把名字传进来,可以直接在默认构造函数中调用基类的构造函数,传入固定的连接字符串名称:
public OrderSystemContext()
:base("OrderSystem")
{
}
如果我们程序中同时存在多个DbContext的子类的时候,Entity Framework会为每个DbContext的子类都创建一个数据库连接,那么我们的程序就保留了很多个数据库连接的实例。如果我们要优化我们的程序,就可以让多个DbContext子类使用同一个数据库连接实例。我们还是要通过重载DbContext的另一个构造函数来实现这个功能。
DbContext的这个构造函数有两个参数,一个是我们要共用的数据库连接的实例,另一个是一个开关,用于控制是否由当前的DbContext子类控制数据库连接实例。如果contextOwnsContext属性为true,那么当DbContext子类Dispose的时候,就会把共用的DbConnection实例也Dispose掉。如果这个值是false,则数据库连接实例就需要由程序员自己写程序释放。
public OrderSystemContext(DbConnection connection, bool contextOwnsConnection)
: base(connection, contextOwnsConnection)
{
}
然后我们可以使用这个构造函数,让我们的DbContext子类使用共用的数据库连接实例。
string connectionString = @"Data Source=XXX\SQL2008R2;Initial Catalog=OrderSystem;User Id=XXX;Password=XXX";
SqlConnection conn = new SqlConnection(connectionString);
OrderSystemContext unitOfWork = new OrderSystemContext(conn,true);
ProductRepository repository = new ProductRepository(unitOfWork);
ProductCatalog catalog = repository.SearchProductCatalog(c => c.CatalogName == "DELL E6400", 1, 10)[0];
Product product = new Product { Catalog = catalog, CreateDate = DateTime.Parse("2010-2-10"), ExpireDate = DateTime.Parse("2012-2-10") };
repository.AddNewProduct(product);
unitOfWork.CommitChanges();
Entity Framework默认会通过一个实现了IDbConnectionFactory接口的类为我们自定义的DbContext类创建数据库连接。Entity Framework默认提供一个SqlConnectionFactory类用来创建SQL Server的数据库连接。Entity Framework Code First中Database.DefaultConnectionFactory属性存储就是SqlConnectionFactory的对象。
你可以初始化一个新的SqlConnectionFactory的实例,把它赋给Database.DefaultConnectionFactory属性,你还可以在初始化SqlConnectionFactory的时候,将一些数据库配置传进去覆盖Code First的默认数据库连接配置
Database.DefaultConnectionFactory = new SqlConnectionFactory(@"Server=XXX\SQL2008R2;Initial Catalog=OrderSystem;User Id=XXX;Password=XXX");
但是有一点比较坑爹,大家一定要牢记,你设置的数据库连接配置中的数据库名是无效的。当我使用上面的代码配置数据库时,建立的数据库的名字不是你在SqlConnectionFactory的构造函数中指定的OrderSystem,而是你的DbContext子类的全名(命名空间.类名)
如果你要是想使用自定义的数据库名称,你需要重载DbContext子类的构造函数。
public OrderSystemContext(string databaseName)
: base(databaseName)
{
}
在你使用SqlConnectionFactory的情况下,你传入的databaseName就是你要访问的数据库的名字,而不像上面的实例中那样是连接字符串的名字。
OrderSystemContext unitOfWork = new OrderSystemContext("OrderSystem");
通过这篇日记,大家已经清楚怎样配置数据库连接。我已经介绍过如何配置数据表中列的属性,下一次日记中,我将介绍一些高级的列属性设置。