一、概述
Entity Framework(实体框架)是一个ORM(对象关系映射)框架,它允许开发人员通过将业务对象映射到数据库中的表,来实现对数据库进行操作。它是一个开源框架,由Microsoft维护和开发。Entity Framework不仅提供了数据访问的解决方案,还支持LINQ(语言集成查询)等功能,使得编写数据库访问代码变得更加简单和直接。
二、基础操作
使用Entity Framework来操作数据库,需要进行以下基本步骤:
1、创建一个继承自DbContext的类,并提供数据库连接字符串。DbContext是应用程序和数据库之间交换数据的主要类。它表示一个特定数据库的上下文。
下面是一个简单的DbContext的示例:
public class MyDbContext : DbContext
{
public MyDbContext() : base("name=MyConnectionString")
{
}
public DbSet
Categories { get; set; }
public DbSet
Products { get; set; }
}
2、创建模型。模型是可持久化数据的实体类。它们映射到数据库的表,在模型中定义的属性则对应于表中的列,为每个模型类设置主键是必选的。
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
public int Id { get; set; }
//省略其它属性
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
}
3、执行CRUD操作。数据库的增删改查操作可以通过DbContext来实现。以查询为例,下面是一个使用LINQ进行查询并返回结果的示例:
using (var context = new MyDbContext())
{
var products = from p in context.Products
where p.CategoryId == 1
select p;
foreach (var product in products)
{
Console.WriteLine(product.Name);
}
}
三、数据迁移
数据迁移是指修改实体类及其属性,从而对数据库架构进行更改。它允许开发人员在不删除数据库并保持数据完整性的同时,对应用程序和数据库架构进行升级。
1、安装Entity Framework迁移工具。在NuGet包管理器控制台中,执行以下命令:
Install-Package EntityFramework
Install-Package EntityFramework.Tools
2、创建迁移脚本。在终端输入以下命令:
dotnet ef migrations add <migration name>
其中,<migration name>是自定义的迁移脚本名称。这个命令会将所有与上一个迁移脚本不同的模型更改写入新的迁移脚本中,并将其应用于数据库。
3、通过迁移脚本更新数据库。在终端输入以下命令:
dotnet ef database update
四、分页技巧
分页是常见的需求,以下是一些常见的分页技巧:
1、使用Skip()和Take()方法。Skip()和Take()方法允许在从数据库检索和处理结果之前跳过一些行,并限制返回的行数。下面是一个简单的示例,该示例从数据库中返回第11-20行的数据:
int pageSize = 10;
int pageNumber = 2;
var query = context.Products.OrderBy(p => p.Name)
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize)
.ToList();
2、使用HasNextPage和HasPreviousPage属性统计物品页数。以下是一个示例方法,该方法接受当前页码、每页的元素数和总记录数,并将总页数、下一页和上一页标志作为out参数输出:
public static void CalculatePageInfo(int currentPage, int itemsPerPage, int totalItems, out int totalPages, out bool hasNextPage, out bool hasPreviousPage)
{
totalPages = totalItems / itemsPerPage;
if (totalItems % itemsPerPage != 0)
{
totalPages++; // 如果有余数,则增加一页
}
hasNextPage = (currentPage < totalPages);
hasPreviousPage = (currentPage > 1);
}
五、存储过程和函数
Entity Framework也支持存储过程和函数。以下是一些例子:
1、使用SqlQuery方法调用存储过程。SqlQuery方法允许执行任意的SQL语句,下面是一个简单的存储过程示例:
var categoryId = new SqlParameter("@categoryId", 1); // 存储过程需要参数categoryId
var products = context.Database.SqlQuery<Product>("EXEC GetProductsByCategoryId @categoryId", categoryId).ToList();
2、使用FunctionAttribute属性和In/Out/Return等修饰符声明函数。以下是一个简单的函数示例,该函数可以接受输入参数和返回值:
[DbFunction("MyNamespace", "MyScalarFunction")]
public static int MyScalarFunction(int input)
{
throw new NotSupportedException(); // 空实现,因为我们不应该在代码中调用函数,而应该将其用在LINQ表达式中
}
然后,可以将它添加到LINQ查询中:
var query = from p in context.Products
select new
{
Id = p.Id,
Name = p.Name,
CategoryId = p.CategoryId,
CategoryName = MyScalarFunction(p.CategoryId) // 使用MyScalarFunction
};
六、并发控制
在多个线程和进程同时访问数据库时,可能会发生并发更新。为了解决这个问题,Entity Framework支持乐观并发控制和悲观并发控制。
1、乐观并发控制。乐观并发控制假定在任何给定时间,每个实体都具有独立的版本,并且在保存实体时进行检查。如果实体版本与数据库中的版本不匹配,则表示实体已被其他用户更新并抛出异常。
var product = context.Products.Find(id);
product.Name = "NewName";
try
{
context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
// 必须获取数据库中的实体以更新本地缓存
ex.Entries.Single().Reload();
}
2、悲观并发控制。悲观并发控制使用锁定机制,在对实体进行修改时阻止其他会话的访问。以下是一个示例,使用SELECT FOR UPDATE语句将数据行锁定:
using (var context = new MyDbContext())
{
using (var dbContextTransaction = context.Database.BeginTransaction())
{
try
{
var product = context.Products.SqlQuery("SELECT * FROM dbo.Products WITH (UPDLOCK, ROWLOCK) WHERE Id = @id", new SqlParameter("@id", id)).Single();
product.Name = "NewName";
context.SaveChanges();
dbContextTransaction.Commit();
}
catch (Exception ex)
{
dbContextTransaction.Rollback();
}
}
}
七、总结
Entity Framework提供了一种简单的方法来访问和操作数据库。从基础操作、数据迁移、分页技巧、存储过程和函数以及并发控制等方面,本文介绍了Entity Framework的常见用法,并提供了代码示例。使用Entity Framework时,请考虑数据量和性能问题,并选择最适合自己的实现方式。