Skip to main content
Code Review

Return to Answer

Commonmark migration
Source Link

###Leaky abstractions

Leaky abstractions

A specific implementation should not leak into an abstraction. By making IUnitOfWork extend IDisposable, that's what you're doing:

public interface IUnitOfWork : IDisposable

The goal of the abstraction, is to abstract implementation details away - in this case, the fact that you're using NHibernate. You had a specific implementation in mind when you created this interface, and that implementation leaked into the abstraction. What if you wanted to implement an IUnitOfWork that worked off a List<T>, for testing purposes?

Not all implementations of IUnitOfWork need to implement IDisposable - better leave that up to the implementation:

public class NHibernateUnitOfWork : IUnitOfWork, IDisposable
{
 private readonly ISession _session;
 /* implementation */
 public void Dispose()
 {
 _session.Dispose();
 }
}
public class TestUnitOfWork : IUnitOfWork
{
 /* implementation */
}

###IQueryable

IQueryable

Every single implementation of the Repository & Unit of Work patterns I have seen, were different. Every single one.

Without seeing what your implementations and client code looks like (/how you're using these interfaces), it's very hard to tell whether you've done something wrong.

For one thing, exposing IQueryable<T> is leaking the query outside your repository, making it possible for client code to call IRepository<T>.FindAll() and then from there, add a Where clause or Join on another repository, which means the repository completely loses control of query materialization, which [unless I missed something] defeats its purpose.

By exposing a IRepository<T> GetRepository<T>() method on your IUnitOfWork, you're also making it possible for the unit of work's clients to own the materialization of the query.

Whether that's good or bad, entirely depends on your architecture; I cannot tell just from the interfaces... I can only raise a flag.

###Leaky abstractions

A specific implementation should not leak into an abstraction. By making IUnitOfWork extend IDisposable, that's what you're doing:

public interface IUnitOfWork : IDisposable

The goal of the abstraction, is to abstract implementation details away - in this case, the fact that you're using NHibernate. You had a specific implementation in mind when you created this interface, and that implementation leaked into the abstraction. What if you wanted to implement an IUnitOfWork that worked off a List<T>, for testing purposes?

Not all implementations of IUnitOfWork need to implement IDisposable - better leave that up to the implementation:

public class NHibernateUnitOfWork : IUnitOfWork, IDisposable
{
 private readonly ISession _session;
 /* implementation */
 public void Dispose()
 {
 _session.Dispose();
 }
}
public class TestUnitOfWork : IUnitOfWork
{
 /* implementation */
}

###IQueryable

Every single implementation of the Repository & Unit of Work patterns I have seen, were different. Every single one.

Without seeing what your implementations and client code looks like (/how you're using these interfaces), it's very hard to tell whether you've done something wrong.

For one thing, exposing IQueryable<T> is leaking the query outside your repository, making it possible for client code to call IRepository<T>.FindAll() and then from there, add a Where clause or Join on another repository, which means the repository completely loses control of query materialization, which [unless I missed something] defeats its purpose.

By exposing a IRepository<T> GetRepository<T>() method on your IUnitOfWork, you're also making it possible for the unit of work's clients to own the materialization of the query.

Whether that's good or bad, entirely depends on your architecture; I cannot tell just from the interfaces... I can only raise a flag.

Leaky abstractions

A specific implementation should not leak into an abstraction. By making IUnitOfWork extend IDisposable, that's what you're doing:

public interface IUnitOfWork : IDisposable

The goal of the abstraction, is to abstract implementation details away - in this case, the fact that you're using NHibernate. You had a specific implementation in mind when you created this interface, and that implementation leaked into the abstraction. What if you wanted to implement an IUnitOfWork that worked off a List<T>, for testing purposes?

Not all implementations of IUnitOfWork need to implement IDisposable - better leave that up to the implementation:

public class NHibernateUnitOfWork : IUnitOfWork, IDisposable
{
 private readonly ISession _session;
 /* implementation */
 public void Dispose()
 {
 _session.Dispose();
 }
}
public class TestUnitOfWork : IUnitOfWork
{
 /* implementation */
}

IQueryable

Every single implementation of the Repository & Unit of Work patterns I have seen, were different. Every single one.

Without seeing what your implementations and client code looks like (/how you're using these interfaces), it's very hard to tell whether you've done something wrong.

For one thing, exposing IQueryable<T> is leaking the query outside your repository, making it possible for client code to call IRepository<T>.FindAll() and then from there, add a Where clause or Join on another repository, which means the repository completely loses control of query materialization, which [unless I missed something] defeats its purpose.

By exposing a IRepository<T> GetRepository<T>() method on your IUnitOfWork, you're also making it possible for the unit of work's clients to own the materialization of the query.

Whether that's good or bad, entirely depends on your architecture; I cannot tell just from the interfaces... I can only raise a flag.

Source Link
Mathieu Guindon
  • 75.5k
  • 18
  • 194
  • 467

###Leaky abstractions

A specific implementation should not leak into an abstraction. By making IUnitOfWork extend IDisposable, that's what you're doing:

public interface IUnitOfWork : IDisposable

The goal of the abstraction, is to abstract implementation details away - in this case, the fact that you're using NHibernate. You had a specific implementation in mind when you created this interface, and that implementation leaked into the abstraction. What if you wanted to implement an IUnitOfWork that worked off a List<T>, for testing purposes?

Not all implementations of IUnitOfWork need to implement IDisposable - better leave that up to the implementation:

public class NHibernateUnitOfWork : IUnitOfWork, IDisposable
{
 private readonly ISession _session;
 /* implementation */
 public void Dispose()
 {
 _session.Dispose();
 }
}
public class TestUnitOfWork : IUnitOfWork
{
 /* implementation */
}

###IQueryable

Every single implementation of the Repository & Unit of Work patterns I have seen, were different. Every single one.

Without seeing what your implementations and client code looks like (/how you're using these interfaces), it's very hard to tell whether you've done something wrong.

For one thing, exposing IQueryable<T> is leaking the query outside your repository, making it possible for client code to call IRepository<T>.FindAll() and then from there, add a Where clause or Join on another repository, which means the repository completely loses control of query materialization, which [unless I missed something] defeats its purpose.

By exposing a IRepository<T> GetRepository<T>() method on your IUnitOfWork, you're also making it possible for the unit of work's clients to own the materialization of the query.

Whether that's good or bad, entirely depends on your architecture; I cannot tell just from the interfaces... I can only raise a flag.

lang-cs

AltStyle によって変換されたページ (->オリジナル) /