随着我深入研究DbContext,DbSet和相关接口,我想知道为什么你需要围绕这些实现实现一个单独的"通用"存储库?
它看起来像DbContext和IDbSet做你需要的一切,并在DbContext中包含"工作单元".
我在这里遗漏了什么,或者似乎人们喜欢无缘无故地添加另一层依赖.
实体框架4,POCO对象和ASP.Net MVC2.我有很多关系,比如BlogPost和Tag实体之间的关系.这意味着在我的T4生成的POCO BlogPost类中,我有:
public virtual ICollection<Tag> Tags {
// getter and setter with the magic FixupCollection
}
private ICollection<Tag> _tags;
Run Code Online (Sandbox Code Playgroud)
我要求一个BlogPost和来自ObjectContext实例的相关标签,并将其发送到另一层(MVC应用程序中的View).稍后我回到更新的BlogPost,更改了属性并更改了关系.例如,它具有标签"A""B"和"C",并且新标签是"C"和"D".在我的特定示例中,没有新的标签,并且标签的属性永远不会改变,因此唯一应该保存的是改变的关系.现在我需要将它保存在另一个ObjectContext中.(更新:现在我尝试在同一个上下文实例中执行,但也失败了.)
问题:我无法正确保存关系.我尝试了我发现的一切:
"不起作用"意味着在大多数情况下我使用给定的"解决方案",直到它不产生错误并至少保存BlogPost的属性.关系会发生什么变化:通常使用新的PK将标签添加到Tag表中,并且保存的BlogPost引用那些而不是原始的.当然返回的标签有PK,在保存/更新方法之前,我检查PK并且它们等于数据库中的PK,所以EF可能认为它们是新对象而那些PK是临时的.
我知道的一个问题,并且可能使得无法找到自动化的简单解决方案:当POCO对象的集合发生更改时,应该通过上面提到的虚拟集合属性发生,因为那时FixupCollection技巧将更新另一端的反向引用多对多关系.但是,当View"返回"更新的BlogPost对象时,这种情况并未发生.这意味着对我的问题可能没有简单的解决方案,但这会让我非常伤心,我会讨厌EF4-POCO-MVC的胜利:(.这也意味着EF无法在MVC环境中做到这一点,无论哪个使用EF4对象类型:(.我认为基于快照的更改跟踪应该发现更改的BlogPost与具有现有PK的标签有关系.
顺便说一句:我认为同一个问题发生在一对多的关系上(谷歌和我的同事这么说).我会在家里尝试一下,但即使这样做对我的应用程序中的六个多对多关系没有帮助:(.
我正在使用本教程伪造我的DbContext并测试:http://refactorthis.wordpress.com/2011/05/31/mock-faking-dbcontext-in-entity-framework-4-1-with-a-generic -repository /
但我必须更改FakeMainModuleContext实现以在我的控制器中使用:
public class FakeQuestiona2011Context : IQuestiona2011Context
{
private IDbSet<Credencial> _credencial;
private IDbSet<Perfil> _perfil;
private IDbSet<Apurador> _apurador;
private IDbSet<Entrevistado> _entrevistado;
private IDbSet<Setor> _setor;
private IDbSet<Secretaria> _secretaria;
private IDbSet<Pesquisa> _pesquisa;
private IDbSet<Pergunta> _pergunta;
private IDbSet<Resposta> _resposta;
public IDbSet<Credencial> Credencial { get { return _credencial ?? (_credencial = new FakeDbSet<Credencial>()); } set { } }
public IDbSet<Perfil> Perfil { get { return _perfil ?? (_perfil = new FakeDbSet<Perfil>()); } set { } }
public IDbSet<Apurador> Apurador { get …Run Code Online (Sandbox Code Playgroud) EF的新手,我注意到使用存储库模式可以真正简化事情并允许我做一些嘲弄.太好了.
我的问题
objectContext的典型用法是尽快销毁,见下文
using (var context = new SchoolEntities())
{
context.AddToDepartments(department);
context.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)
使用Repository模式我注意到没有人真正使用"使用模式",例如
using (var repository= new Repository<Student>(new MyContext))
{
repository.Add(myStudentEntity)
repository.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)
应该是我们应该尽快处理上下文,否则内存可能会泄漏或变得非常大?
任何人都可以澄清吗?非常感谢.
尽管这样的问题被多次询问,我仍在努力理解存储库和工作单元模式之间的关系.基本上我还是不明白哪个部分会保存/提交数据更改 - 存储库或工作单元?
由于我看到的每个例子都与使用这些和数据库/ OR映射器有关,所以让我们做一个更有趣的例子 - 让数据保存在数据文件中的文件系统中; 根据模式,我应该能够做到这一点,因为数据的去向与此无关.
所以对于一个基本实体:
public class Account
{
public int Id { get; set; }
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我想会使用以下接口:
public interface IAccountRepository
{
Account Get(int id);
void Add(Account account);
void Update(Account account);
void Remove(Account account);
}
public interface IUnitOfWork
{
void Save();
}
Run Code Online (Sandbox Code Playgroud)
我认为在使用方面它看起来像这样:
IUnitOfWork unitOfWork = // Create concrete implementation here
IAccountRepository repository = // Create concrete implementation here
// Add a new account
Account account = new Account() …Run Code Online (Sandbox Code Playgroud) 存储库模式用于从特定数据库和对象关系映射技术(如EF)中抽象使用.因此,如果我决定这样做,我可以在将来轻松替换(例如)我的实体框架映射与Linq to SQL.
但是当我使用EF时,我从模型中获得了我的实体类 - 也就是说它们是从该可视化图中生成的.如果我在我的存储库中使用这个生成的实体类,然后决定用其他东西替换EF,那么我将删除那个可视化实体图,这也意味着删除类吧?
我要解决的问题是我的存储库将依赖于实体框架,即数据访问层,因为它将使用EF生成的类.
如何删除此依赖项?
另请注意,我使用EF主要是因为它能够从该可视化图生成所有内容 - 我只是设计图表并让它为我生成所有外键等数据库.我非常喜欢,甚至不想想想SQL命令.
.net asp.net-mvc entity-framework repository repository-pattern
想知道我是否需要使用Genericrepository模式和UnitOfWork来模拟存储库.我正在使用MOQ.Is它现在是多余的,因为我注意到EF 4.1有IDBSet.
我还没弄明白如何编写一些通用的IDBSet.如果你有一个实例IDBSet的例子,你能告诉我吗?
有什么建议?
unit-testing mocking unit-of-work repository-pattern entity-framework-4.1
好吧,不确定这是否是正确的标题,但基本上我在使用MVC应用程序中的存储库时遇到了很多问题,您可以用另一组存储库替换一组存储库,实现不同的数据存储技术.
例如,假设我想为我的应用程序使用Entity Framework.但是,我还希望在硬编码列表中实现一组测试数据.我想有一组接口(IUserRepository,IProductRepository等 - 我们暂不讨论现在更通用的IRepository <T>)这两种方法都可以实例化.然后,使用(比方说)Ninject或Castle Windsor等依赖注入工具,我可以在实体框架提供程序(访问实际数据库)和测试提供程序(访问列表)之间来回切换.
简而言之,问题在于:
- 如果要使用Entity Framework,则希望您的存储库返回IQueryable <SomeType>.
- 如果你打算使用硬编码列表,你不希望你的存储库返回IQueryable,因为它大大增加了开销,而且,Linq to Entities与Linq到Objects有很大的不同,导致代码中的许多麻烦这两个提供商都很常见.
换句话说,我发现最好的方法是隔离存储库中所有依赖于EF的代码,以便存储库本身返回IEnumerable或IList或其他类似的东西 - 然后EF和其他一些技术都可以使用相同的存储库.因此,所有IQueryable都将包含在EF存储库中.这样,您可以将Linq实体与EF存储库一起使用,将Linq添加到具有测试存储库的对象.
然而,这种方法将大量的业务逻辑放入存储库中,并导致许多重复的代码 - 即使实现有些不同,逻辑也必须在每个存储库中重复.
存储库作为这个非常薄的层并且只是连接到数据库的整个想法随后丢失 - 存储库是业务逻辑的"存储库"以及数据存储连接.你不能只有查找,保存,更新等.
我无法解决需要隔离提供程序相关代码和在集中位置拥有业务逻辑之间的这种差异.
有任何想法吗?如果有人能够指出一个解决这个问题的实现的例子,我将非常感激.(我已经阅读了很多内容,但找不到任何专门讨论这些问题的内容.)
更新:
我想我开始觉得可能不可能为不同的提供者换出存储库 - 例如,如果你要使用Entity Framework,你只需将整个应用程序用于实体框架.单元测试?我正在努力解决这个问题.到目前为止,我的做法是使用硬编码数据建立一个单独的存储库,并将其用于单元测试,以及在设置数据库之前测试应用程序本身.我想我将不得不寻找一个不同的解决方案,也许是一些嘲弄工具.
但后来提出了为什么使用存储库的问题,特别是为什么使用存储库接口.我正在研究这个问题.我认为确定最佳实践是需要进行一些研究.
asp.net-mvc design-patterns entity-framework repository-pattern
我有一个具体的存储库实现,它返回实体的IQueryable:
public class Repository
{
private AppDbContext context;
public Repository()
{
context = new AppDbContext();
}
public IQueryable<Post> GetPosts()
{
return context.Posts;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,我的服务层可以根据其他方法(其中,分页等)的需要执行LINQ
现在我的服务层设置为返回IEnumerable:
public IEnumerable<Post> GetPageOfPosts(int pageNumber, int pageSize)
{
Repository postRepo = new Repository();
var posts = (from p in postRepo.GetPosts() //this is IQueryable
orderby p.PostDate descending
select p)
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize);
return posts;
}
Run Code Online (Sandbox Code Playgroud)
这意味着在我的代码隐藏中,如果我想绑定到转发器或其他控件,我必须执行ToList().
这是处理返回类型的最佳方法,还是在从服务层方法返回之前需要转换为列表?
asp.net-mvc ×4
unit-of-work ×3
.net ×2
c# ×2
unit-testing ×2
architecture ×1
asp.net ×1
mocking ×1
poco ×1
repository ×1
tdd ×1