Omu*_*Omu 5 entity-framework repository entity-framework-4
我正在尝试用ef4 ctp5实现存储库模式,我想出了一些东西,但我不是ef的专家,所以我想知道我做的是不是很好.
这是我的数据库上下文
public class Db : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Role> Roles { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
和存储库:(简化)
public class Repo<T> : IRepo<T> where T : Entity, new()
{
private readonly DbContext context;
public Repo()
{
context = new Db();
}
public IEnumerable<T> GetAll()
{
return context.Set<T>().AsEnumerable();
}
public long Insert(T o)
{
context.Set<T>().Add(o);
context.SaveChanges();
return o.Id;
}
}
Run Code Online (Sandbox Code Playgroud)
Kal*_*exx 10
您需要退后一步,考虑一下存储库应该做什么.存储库用于检索记录,添加记录和更新记录.您创建的存储库几乎不处理第一种情况,处理第二种情况但不能有效处理,并且根本不处理第三种情况.
大多数通用存储库都有一个接口
public interface IRepository<T> where T : class
{
IQueryable<T> Get();
void Add(T item);
void Delete(T item);
void CommitChanges();
}
Run Code Online (Sandbox Code Playgroud)
对于检索记录,您不能只调用整个集合,AsEnumerable()因为它会将该表的每个数据库记录加载到内存中.如果您只希望用户使用用户名username1,则不需要为数据库下载每个用户,因为这将是一个非常大的数据库性能命中,并且大客户端性能达不到任何好处.
相反,正如您将从我上面发布的界面中看到的那样,您想要返回一个IQueryable<T>对象. IQuerable允许调用存储库的任何类使用Linq并向数据库查询添加过滤器,并且一旦运行IQueryable,它就完全在数据库上运行,只检索所需的记录.数据库在对系统进行排序和过滤方面要好得多,因此最好尽可能多地在数据库上进行.
现在关于插入数据,你有正确的想法,但你不想SaveChanges()立即打电话.原因是Savechanges()在所有数据库操作排队后最好调用.例如,如果要在一个操作中创建用户及其配置文件,则无法通过方法,因为每次Insert调用都会导致数据插入到数据库中.
相反,你想要的是将Savechanges()调用分离到CommitChanges我上面的方法.
这也是处理数据库中更新数据所必需的.为了更改实体的数据,实体框架会跟踪它收到的所有记录,并监视它们以查看是否进行了任何更改.但是,您仍然必须告诉实体框架将所有已更改的数据发送到数据库.电话会发生这种情况context.SaveChanges().因此,您需要将其作为单独的调用,以便您能够实际更新当前实现无法处理的已编辑数据.
实体框架会跟踪实体所跟踪的上下文,如果您尝试在一个上下文中更新另一个实体,则会出现异常.当您开始编辑彼此相关的实体时,可能会出现这种情况.这也意味着您的SaveChanges()调用不是事务性的,并且每个实体都在其自己的事务中更新/添加/删除,这可能会变得混乱.
我在我的存储库中对此的解决方案是将其DbContext传递到构造函数中的存储库中.
我可能会为此投票,但DbContext已经是一个存储库.当您将域模型公开为具体DbContext的集合属性时,EF CTP5会为您创建一个存储库.它提供了一个类似于接口的集合,用于访问域模型,同时允许您传递查询(作为linq或spec对象)以过滤结果.
如果您需要一个界面,CTP5不会为您提供一个界面.我已经将自己包装在DBContext中,并简单地从对象中公开了可公开获得的成员.它是可测试性和DI的适配器.
如果我说的话显然不明显,我会评论澄清.
| 归档时间: |
|
| 查看次数: |
1937 次 |
| 最近记录: |