Generic Repository

♀尐吖头ヾ 提交于 2019-12-03 10:03:52

A lot of questions in there, and some of the answers might be subjective/opionated, but i'll roll with the punches.

IQueryable vs specific methods.

I actually agree with you. I don't like the idea of having lots and lots of methods for defining all the different operations on my repository. I prefer to allow the calling code to supply the specification. Now, my calling code is not my presentation - it's a domain service/BLL. So it's not like we're giving full power to the UI, we're just allowing our repository to stay very generic. DDD purists would argue that repositories are abstractions of your domain model, and therefore should serve specific domain operations. I'll leave that open for you to decide. Also, if your using IQueryable, then your forcing an "unknown" LINQ provider to be used. Not a problem for me, as i will always be using something that works off LINQ (Entity Framework, for example). But this is another problem that DDD-purists have.

What about when you want to search on first name and last name

Well, i use Expression<Func<T,bool>> for my domain services, so i can do this:

var customers = repository.FindAll<Customer>(x => x.FirstName == "Bob" && x.LastName == "Saget");

If you don't like that, you could use the Specification pattern to make use of AND/OR-type code.

Deleting customer address

Well generally speaking, you should have one repository per aggregate root. Without knowing your domain model, it sounds like "Customer" is an aggregate root, and "CustomerAddress" is an aggregate, which is always associated to a "Customer" (e.g cannot exist without one).

Therefore, there you don't require a CustomerAddressRepository. CustomerAddress operations should be done via your CustomerAddress repository.

This is why i like to create a GenericRepository<T> implementation of IRepository<T> which implements core operations on the aggregate (Find, Add, Remove), then even more specific implementations deriving from GenericRepository<T>.

Here's how i would handle Customer Repository. Create a GenericRepository<T>, which implements IRepository<T> core operations. Then create another interface for ICustomerRepository, which also implements IRepository<T>.

Now, create a implementation called CustomerRepository, which inherits the core repository implementation from GenericRepository<T>, and also extends this to allows extra operations (such as removing address).

public class CustomerRepository : GenericRepository<Customer>, ICustomerRepository
{
   // inherits, for example:
   // IQueryable<Customer> Query<Customer>();

   public void Remove(Address address)
   {
       // get the customer (if you havent already got it)
       var cust = ctx.Customers.SingleOrDefault(x => x.CustId == address.CustId);
       cust.Addresses.Remove(address);
   }
}

And your ICustomerRepository would look like this:

public interface ICustomerRepository : GenericRepository<Customer>, IRepository<Customer>
{
    // inherited from GenericRepository<Customer>
    //IQueryable<T> Query<T>();
    //void Attach(object entity);
    //void ForDeletion(object entity);
    //void SaveChanges();
    void Remove(Address address);
}

Know what i mean? Start with really generic repositories, then get more specific as you require.

You do not require a CustomerAddressRepository. Perform the operations via the CustomerRepository as i have shown above.

HTH.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!