简体   繁体   English

使用UnitOfWork和存储库模式与实体框架

[英]using UnitOfWork and Repository Pattern with Entity Framework

I'm gonna to use repository and UnitOfwork in my data access layer to do this take a look at one contact aggregateroot 我将在我的数据访问层中使用存储库和UnitOfwork来执行此操作,查看一个联系人aggregateroot

 public interface IAggregateRoot
    {
    }

this is my Generic repository interface : 这是我的Generic存储库接口:

 public interface IRepository<T>
        {
            IEnumerable<T> GetAll();
            T FindBy(params Object[] keyValues);
            void Add(T entity);
            void Update(T entity);
            void Delete(T entity);

        }

and my POCO Contact class in Model 和我在模型中的POCO Contact类

 public class Contact :IAggregateRoot
        {
            public Guid Id { get; set; }
            public string Name { get; set; }
            public string Email { get; set; }
            public string Title { get; set; }
            public string Body { get; set; }
            public DateTime CreationTime { get; set; }
        }

and this my IContactRepository that inherit from IRepository and also maybe has it is own method 这是我继承自IRepository的IContactRepository,也可能是自己的方法

 public interface IContactRepository : IRepository<Contact>
        {
        }

Now I have done in IUitOfWork and UnitOfwork like this 现在我已经完成了IUitOfWork和UnitOfwork

public interface IUnitOfWork 
    {
        IRepository<Contact> ContactRepository { get; }
    }

public class UnitOfWork : IUnitOfWork
    {
        private readonly StatosContext _statosContext = new StatosContext();
        private IRepository<Contact> _contactUsRepository;

 public IRepository<Contact> ContactRepository
        {
            get { return _contactUsRepository ?? (_contactUsRepository = new Repository<Contact>(_statosContext)); }
        }
}

also about my Repository 关于我的存储库

public class Repository<T> : IRepository<T> where T : class, IAggregateRoot
    {
       //implementing methods 
    }

I can do all CRUD operation with accessing Repositories with UnitOfwork in Service , example : 我可以通过Service中的UnitOfwork访问存储库来执行所有CRUD操作,例如:

_unitOfWork.ContactRepository.Add(contact);
            _unitOfWork.SaveChanges();

but I want to do like this 但我想这样做

_ _

ContactRepository.Add(contact);
            _unitOfWork.SaveChanges();

(get CRUD and generic method via _ContactRepository No by _unitOfWork.ContactRepository) Because I want to get ContactRepository method to some specific queries , anybody help please ?? (通过_unitOfWork.ContactRepository通过_ContactRepository No获取CRUD和泛型方法)因为我想获得一些特定查询的ContactRepository方法,所以有人帮忙吗?

It's not a direct answer to your question, but it might simplify things a little bit and reduce duplication. 它不是您问题的直接答案,但它可以简化一些事情并减少重复。

When you use eg EntityFramework Power Tools to reverse-engineer Code First (or just use Code First in general), you end up with the DbContext class that serves as a UoW and repository in one, eg: 当您使用例如EntityFramework Power Tools对Code First进行逆向工程时(或者通常仅使用Code First),您最终会使用DbContext类作为UoW和存储库,例如:

public partial class YourDbContext : DbContext
{
    public DbSet<Contact> Contacts {get; set;}
}

Now, if you want things to be testable, there's an easy way: introduce a very thin interface: 现在,如果你想让事情变得可测试,那么有一个简单的方法:引入一个非常精简的界面:

public interface IDbContext
{
    IDbSet<T> EntitySet<T>() where T : class;
    int SaveChanges();
    //you can reveal more methods from the original DbContext, like `GetValidationErrors` method or whatever you really need.
}

then make another file with second part of the partial class: 然后使用分部类的第二部分创建另一个文件:

public partial class YourDbContext : IDbContext
{
     public IDbSet<T> EntitySet<T>() where T : class
     {
         return Set<T>();
     }
}

Ta-da! 当当! Now you can inject IDbContext with YourDbContext backing it up: 现在您可以使用YourDbContext注入IDbContext

//context is an injected IDbContext:
var contact = context.EntitySet<Contact>().Single(x => x.Id == 2);    
contact.Name = "Updated name";
context.EntitySet<Contact>().Add(new Contact { Name = "Brand new" });
context.SaveChanges();

Now if you want to have control over the disposal of the context, then you'd have to write your own ( gasp ) IDbContextFactory (generic or not, depending what you need) and inject that factory instead. 现在,如果您想控制上下文的处理,那么您必须编写自己的( 喘气IDbContextFactory (通用与否,根据您的需要)并注入该工厂。

No need to write your own Find , Add or Update methods now, DbContext will handle that appropriately, it's easier to introduce explicit transactions and everything is nicely hidden behind interfaces ( IDbContext , IDbSet ). 现在不需要编写自己的FindAddUpdate方法, DbContext将适当地处理它,更容易引入显式事务,并且一切都很好地隐藏在接口后面( IDbContextIDbSet )。

By the way, the IDbContextFactory would be an equivalent to NHibernate's ISessionFactory and IDbContext - ISession . 顺便说一句, IDbContextFactory将等同于NHibernate的ISessionFactoryIDbContext - ISession I wish EF had this out of the box, too. 我希望EF也能开箱即用。

I agree with the Doctor, DbContext is already a UnitOfWork, and adding another UoW abstraction on top of it is typically redundant, unless you think it's highly likely you might switch database technologies in the future. 我同意Doctor,DbContext已经是一个UnitOfWork,并且在它之上添加另一个UoW抽象通常是多余的,除非你认为你很可能在未来转换数据库技术。

I don't agree, however, with treating DbSet's as repositories, since this tightly couples your queries to the methods that use them. 但是,我不同意将DbSet视为存储库,因为这会将查询与使用它们的方法紧密结合。 If you need to change a query, you have to do it everywhere you use it. 如果您需要更改查询,则必须在使用它的任何地方执行此操作。

I prefer to either use a stand-alone repository (or service interface, they serve similar functions) or to use more of a CQRS system for Command/Query Seperation, an use query objects. 我更喜欢使用独立的存储库(或服务接口,它们提供类似的功能),或者使用更多的CQRS系统进行命令/查询分离,即使用查询对象。

Inside the UnitOfWork class you need to implement DBContext or ObjectContext. 在UnitOfWork类中,您需要实现DBContext或ObjectContext。

UnitOfWork segregates all transactions regardless of the system. 无论系统如何,UnitOfWork都会隔离所有事务。 EF is only for DB connection. EF仅用于数据库连接。 Even if your system is only using DB still it is better to keep a separate UnitOfWork class for future expansions. 即使您的系统仅使用数据库,最好还是保留一个单独的UnitOfWork类以用于将来的扩展。

And inside the unit of work Commit(), you can call the internally implemented DBContext.SaveChanges(). 在工作单元Commit()中,您可以调用内部实现的DBContext.SaveChanges()。

This DBcontext will be accessible to all repositories declared inside unitofwork. 单元工作中声明的所有存储库都可以访问此DBcontext。 So repositories add or delete from DBcontext and unitOfwork commits it. 所以在DBcontext中添加或删除存储库,unitOfwork会提交它。

When you have scenarios spanning different storages eg: Cloud Blobs, table storage etc. You could implement them inside UnitofWork just like you implemented a EF context. 当您拥有跨越不同存储的场景时,例如:云Blob,表存储等。您可以在UnitofWork中实现它们,就像您实现EF上下文一样。 And some repositories can access Table Storage and some EF context. 一些存储库可以访问表存储和一些EF上下文。

Tip: Implementing ObjectContext instead of DBContext gives you an edge in caching scenarios. 提示:实现ObjectContext而不是DBContext为缓存方案提供了优势。 And you have more options in extending your framework. 您可以在扩展框架方面有更多选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM