I am using Entity Frameowrk 4.0 and I am calling a stored procedure which returns an ObjectResult and I tried to use MOQ and have not been able to mock ObjectResult. Has anybody been able to mock ObjectResult using moq?
TIA
Yaz
I have this problem too; I'm using database-first design, and the EF 4.x DbContext Generator template to generate my DbContext.
I'm modifying the context generator in the following ways:
Instead of DbSet<T> for entity sets, I am returning IDbSet<T>; this allows me to use InMemoryDbSet<T> for unit testing (Google for implementations);
Instead of ObjectResult<T> for stored procedures, I am returning IEnumerable<T>. Inside the virtual method created for the stored procedure, I load the ObjectResult<T> into a List<T> and return that;
Finally, I extract an interface exposing the entity sets and function imports. This means I can then mock the entire DbContext for super-speedy unit tests. You should still write integration tests that test the database functionality for real, of course.
ObjectResult (according to the MSDN docs) is a sealed class as such you cannot mock it. The way Mocking libraries like Moq work is that when you do something like
Mock<Foo> fooMock = new Mock<Foo>();
It generates (using Reflection.Emit and various other magic tricks) a class that looks a little like this
public class FooMockingProxy : Foo {
public override void This() {
// Mocking interceptors to support Verify and Setup
}
public override string That() {
// Mocking interceptors to support Verify and Setup
}
}
i.e. It takes the class (interface) you want to Mock and subclasses it (or implements it in the case of an interface). This allows it to put in instrumentation that allows it to check if a method has been called, or returns a certain value (this supports the various Setup and Verify methods). The restrictions to this method of mocking are:-
Sealed classes (can't be subclassed)
Private members (can't be accessed from a subclass)
Methods or properties classes that are not virtual (and therefore cannot be overriden).
One technique you can take when approaching sealed classes is to wrap them in some kind of interface that is Mockable. Alternatively you can try and Mock an interface that the sealed class implements that only your code consumes.
ObjectResult is typically used with Linq therefore it is mainly used as IEnumerable. Even though object is sealed, you can mock it and setup IEnumerable behavior.
Here is some sample code where TResult is the stored procedure result type and TDbContext is the DbContext and it will return 1 item.
var valueEnumerator = new TResult[] { new TResult() }.GetEnumerator();
var mockStoredProcedure = new Mock<ObjectResult<TResult>();
mockStoredProcedure.Setup(x => x.GetEnumerator()).Returns(valueEnumerator);
var mockEntities = new Mock<TDbContext>();
mockEntities.Setup(x => x.[stored procedure method]()).Returns(mockStoredProcedure.Object);
You can add any values to array in example above or use any other collection (you only need the enumerator).
Give this code a try. It works for me with EF 6.1.2 and Moq 4.2
I could not find a way to mock a sealed class, and wanted to test that the parameters of a stored procedure matched the entity model. Here is my solution:
namespace CardiacMonitoringTest
{
[TestClass]
public class CardiacMonitoringDataTest
{
[TestMethod]
public void TestEntityStoredProcedure()
{
List<string> SPExceptions = new List<string>();
SPExceptions.Add("AfibBurdenByDay");
SPExceptions.Add("GetEventTotalsByCategory");
EntitiesCon db = new EntitiesCon();
foreach (MethodInfo mi in typeof(EntitiesCon).GetMethods())
{
string ptype = mi.ReturnType.Name;
if (ptype.IndexOf("ObjectResult") > -1)
{
List<SqlParameter> ExtractedParameters = SPListParm(ConfigurationManager.ConnectionStrings["CardiacMonitoring"].ConnectionString, mi.Name);
ExtractedParameters = ExtractedParameters.Where(a => a.ParameterName != "#RETURN_VALUE" && a.ParameterName != "#TABLE_RETURN_VALUE").ToList();
ParameterInfo[] EntityParameters = mi.GetParameters();
if ((from b in SPExceptions where b.ToLower() == mi.Name.ToLower() select b).Count() > 0)
{
continue;
}
foreach (ParameterInfo pi in EntityParameters)
{
try
{
Assert.IsTrue(
(from a in ExtractedParameters where pi.Name.ToLower() == a.ParameterName.Replace("#", "").ToLower() select a).Count() == 1);
}
catch (Exception ex)
{
Trace.WriteLine("Failed SP:" + mi.Name + " at parameter:" + pi.Name);
throw (ex);
}
try
{
Assert.IsTrue(EntityParameters.Count() == ExtractedParameters.Count());
}
catch (Exception ex)
{
Trace.WriteLine("Failed SP:" + mi.Name + " on parameter count:" + EntityParameters.Count() + " with detected count as:" + ExtractedParameters.Count());
throw (ex);
}
}
}
}
}
private List<SqlParameter> SPListParm(string ConnectionString, string SPName)
{
try
{
SqlConnection conn = new SqlConnection(ConnectionString);
SqlCommand cmd = new SqlCommand(SPName, conn);
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
SqlCommandBuilder.DeriveParameters(cmd);
SqlParameter[] prmDetectParameters = new SqlParameter[cmd.Parameters.Count];
cmd.Parameters.CopyTo(prmDetectParameters, 0);
List<SqlParameter> toReturn = new List<SqlParameter>();
toReturn.AddRange(prmDetectParameters);
return (toReturn);
}
catch (Exception ex)
{
Trace.WriteLine("Failed detecting parameters for SP:" + SPName);
throw (ex);
}
}
}
}
Related
I can make it work, but I want to know what the best practice is and why. I have a Controller, a Model, and a Repository and now I want to Unit Test the Controller. I am just writing a simple test to ensure that the correct view is being returned.
This is my method in the controller:
public ActionResult Selections(SelectionsViewModel model)
{
for (int i = 0; i < model.Sends.Count; i++)
{
Send send = new Send(new SendService(new Database().GetConnectionString()))
{
SendID = model.Sends[i].SendID,
Title = model.Sends[i].Title,
Subject = model.Sends[i].Subject,
SentDate = model.Sends[i].SentDate,
TimesViewed = model.Sends[i].TimesViewed,
Include = model.Sends[i].Include,
Exclude = model.Sends[i].Exclude
};
send.UpdateIncludeExclude();
}
return View(model);
}
Here is my GetConnectionString() method in the Database class that is being sent via my SendService constructor.
public string GetConnectionString()
{
return System.Configuration.ConfigurationManager.ConnectionStrings["DEVConnectionString"].ToString();
}
And lastly, my unit test:
[Test]
public void TestAssignmentSelections()
{
var obj = new AssignmentController();
var actResult = obj.Selections() as ViewResult;
NUnit.Framework.Assert.That(actResult.ViewName, Is.EqualTo("Selections"));
}
Now, my unit test fails, and I get why. My unit test project has no access to the web.config of the project I am testing where my connection string resides.
I've done some research, and apparently just adding a web.config to my unit test project and putting the connection string in there as well will make it work.. but that seems like a hack.
What's the best way to go about this? Is there another way to write my code to accommodate for this?
You want to make your controller unit testable ? Don't do this.
new SendService(
With this code,you are hardcoding your concrete service implementation & your data access code implementation. In your unit test, you should not be really accessing the data from your database. Instead you should be providing a mock data access implementation.
Here comes interfaces, you need to create an interface for your SendService.
public interface ISendService
{
void SomeMethod();
}
now your SendService will be a concrete implementation of this interface
public class SendService : ISendService
{
public void SomeMethod()
{
// Do something
}
}
Now update your controller to have a constructor where we will inject an implementation of ISendService.
public class YourController : Controller
{
private ISendService sendService;
public YourController(ISendService sendService)
{
this.sendService = sendService;
}
public ActionResult YourActionMethod()
{
// use this.sendService.SomeMethod();
}
}
And you may use some dependency injection frameworks to tell the MVC framework which implementation of the interface to use when the code runs. If you are using MVC6,It has an inbuilt dependency injection provider you can use. So go to your Startup class and in your ConfigureServices method, you can map an interface to a concrete implementation.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ISendService, SendService>();
}
}
If you are in a previous version of MVC, You may consider DI frameworks like Unity,Ninject etc. You can do the same approach for your Data access later / Service layers. ie: Create an interface for data access and inject that to your SendService.
public Interface IDataAccess
{
string GetName(int id);
}
and an implementation which uses your specific data access code/ORM
public class EFDataAccess : IDataAccess
{
public string GetName(int id)
{
// return a string from db using EF
}
}
So now your Service class will be
public class SendService : ISendService
{
private IDataAccess dataAccess;
public SendService(IDataAccess dataAccess)
{
this.dataAccess=dataAccess;
}
// to do : Implement methods of your ISendService interface.
// you may use this.dataAccess in those methods as needed.
}
In your unit tests, you can create a mock implementation of your interfaces which returns static data instead of accessing the database.
For example, If you are using Moq mocking framework, you can do this.
var m = new Mock<IDataAccess>();
var m.Setup(s=>s.GetName(It.IsAny<int>())).Returns("Test");
var s = new SendService(m);
var result= s.SomeMethod();
In my generic repository I need to write generic Save method which will edit existed or add new entity depending on id.
public void Save<T>(T entity) where T : TEntity, IKeyId
{
if (ObjectSet.Any(r => (r as IKeyId).KeyId == entity.KeyId))
{
Edit(entity);
}
else
{
Add(entity);
}
}
But Linq generate exception when I try do Any( r=> (r as IKeyId)....
The 'TypeAs' expression with an input of type 'MyProg.DAL.Appeal' and a check of type 'Claimstrak.DAL.Interfaces.IKeyId' is not supported. Only entity types and complex types are supported in LINQ to Entities queries.
How to write it correct?
Well, the truth is that you dont need to use the ObjectSet, you can just use DbContext to do this, in a much more easy way.
Bu, i would tell that this is not a good pattern to use, to call a Save() in a repository. I would recomend that you consider the .SaveSession() of the Context only after all was done, this way you can do a lot of things befose making a round trip to te database.
So, you should make a method like this, but not call the SaveChanges(), instead of a Save() method, to a UpdateOrInsert() and them, after all is done you call the .Save()
But i will give the examplefollowing your request (but i dont recommend, i recommend you separate IUnitOfWork from IRepository)
See how the code is very simple:
interface IKeyId
{
int Id { get; set; }
}
DbContext context = new YourContext();
public bool Save<TEntity>(TEntity entity) where TEntity : class, IKeyId
{
return (entity.Id == 0) ? Add<TEntity>(entity) : Edit<TEntity>(entity);
}
public bool Edit<TEntity>(TEntity entity) where TEntity : class, IKeyId
{
var set = context.Set<TEntity>();
set.Attach(entity);
return true;
}
public bool Add<TEntity>(TEntity entity) where TEntity : class, IKeyId
{
var set = context.Set<TEntity>();
set.Add(entity);
return true;
}
I use a similar approach im my repositories, i have changed the T4 (.tt file) that generates the POCO classes from my database to excplicitly implement some interfaces that i have, such as IAuditable, IValidatable and other, so the T4 automaticaly implement those interfaces in the classes.
I have this really basic code in a MVC controller action. It maps an Operation model class to a very basic OperationVM view-model class .
public class OperationVM: Operation
{
public CategoryVM CategoryVM { get; set; }
}
I need to load the complete list of categories in order to create a CategoryVM instance.
Here's how I (try to) create a List<OperationVM> to show in the view.
public class OperationsController : Controller {
private SomeContext context = new SomeContext ();
public ViewResult Index()
{
var ops = context.Operations.Include("blah...").ToList();
Mapper.CreateMap<Operation, OperationVM>()
.ForMember(
dest => dest.CategoryVM,
opt => opt.MapFrom(
src => CreateCatVM(src.Category, context.Categories)
// trouble here ----------------^^^^^^^
)
);
var opVMs = ops.Select(op => Mapper.Map<Operation, OperationVM>(op))
.ToList();
return View(opVMs);
}
}
All works great first time I hit the page. The problem is, the mapper object is static. So when calling Mapper.CreateMap(), the instance of the current DbContext is saved in the closure given to CreateMap().
The 2nd time I hit the page, the static map is already in place, still using the reference to the initial, now disposed, DbContext.
The exact error is:
The operation cannot be completed because the DbContext has been disposed.
The question is: How can I make AutoMapper always use the current context instead of the initial one?
Is there a way to use an "instance" of automapper instead of the static Mapper class?
If this is possible, is it recommended to re-create the mapping every time? I'm worried about reflection slow-downs.
I read a bit about custom resolvers, but I get a similar problem - How do I get the custom resolver to use the current context?
It is possible, but the setup is a bit complicated. I use this in my projects with help of Ninject for dependency injection.
AutoMapper has concept of TypeConverters. Converters provide a way to implement complex operations required to convert certain types in a separate class. If converting Category to CategoryVM requires a database lookup you can implement that logic in custom TypeConverter class similar to this:
using System;
using AutoMapper;
public class CategoryToCategoryVMConverter :
TypeConverter<Category, CategoryVM>
{
public CategoryToCategoryVMConverter(DbContext context)
{
this.Context = context;
}
private DbContext Context { get; set; }
protected override CategoryVM ConvertCore(Category source)
{
// use this.Context to lookup whatever you need
return CreateCatVM(source, this.Context.Categories);
}
}
You then to configure AutoMapper to use your converter:
Mapper.CreateMap<Category, CategoryVM>().ConvertUsing<CategoryToCategoryVMConverter>();
Here comes the tricky part. AutoMapper will need to create a new instance of our converter every time you map values, and it will need to provide DbContext instance for constructor. In my projects I use Ninject for dependency injection, and it is configured to use the same instance of DbContext while processing a request. This way the same instance of DbContext is injected both in your controller and in your AutoMapper converter. The trivial Ninject configuration would look like this:
Bind<DbContext>().To<SomeContext>().InRequestScope();
You can of course use some sort of factory pattern to get instance of DbContext instead of injecting it in constructors.
Let me know if you have any questions.
I've found a workaround that's not completely hacky.
Basically, I tell AutoMapper to ignore the tricky field and I update it myself.
The updated controller looks like this:
public class OperationsController : Controller {
private SomeContext context = new SomeContext ();
public ViewResult Index()
{
var ops = context.Operations.Include("blah...").ToList();
Mapper.CreateMap<Operation, OperationVM>()
.ForMember(dest => dest.CategoryVM, opt => opt.Ignore());
var opVMs = ops.Select(
op => {
var opVM = Mapper.Map<Operation, OperationVM>(op);
opVM.CategoryVM = CreateCatVM(op.Category, context.Categories);
return opVM;
})
.ToList();
return View(opVMs);
}
}
Still curious how this could be done from within AutoMapper...
The answer from #LeffeBrune is perfect. However, I want to have the same behavior, but I don't want to map every property myself. Basically I just wanted to override the "ConstructUsing".
Here is what I came up with.
public static class AutoMapperExtension
{
public static void ConstructUsingService<TSource, TDestination>(this IMappingExpression<TSource, TDestination> mappingExression, Type typeConverterType)
{
mappingExression.ConstructUsing((ResolutionContext ctx) =>
{
var constructor = (IConstructorWithService<TSource, TDestination>)ctx.Options.ServiceCtor.Invoke(typeConverterType);
return constructor.Construct((TSource)ctx.SourceValue);
});
}
}
public class CategoryToCategoryVMConstructor : IConstructorWithService<Category, CategoryVM>
{
private DbContext dbContext;
public DTOSiteToHBTISiteConverter(DbContext dbContext)
{
this.dbContext = dbContext;
}
public CategoryVM Construct(Category category)
{
// Some commands here
if (category.Id > 0)
{
var vmCategory = dbContext.Categories.FirstOrDefault(m => m.Id == category.Id);
if (vmCategory == null)
{
throw new NotAllowedException();
}
return vmCategory;
}
return new CategoryVM();
}
}
// Initialization
Mapper.Initialize(cfg =>
{
cfg.ConstructServicesUsing(type => nInjectKernelForInstance.Get(type));
cfg.CreateMap<Category, CategoryVM>().ConstructUsingService(typeof(CategoryToCategoryVMConstructor));
};
I have an application using ASP.NET MVC, Unity, and Linq to SQL.
The unity container registers the type AcmeDataContext which inherits from System.Data.Linq.DataContext, with a LifetimeManager using HttpContext.
There is a controller factory which gets the controller instances using the unity container. I set-up all my dependencies on the constructors, like this:
// Initialize a new instance of the EmployeeController class
public EmployeeController(IEmployeeService service)
// Initializes a new instance of the EmployeeService class
public EmployeeService(IEmployeeRepository repository) : IEmployeeService
// Initialize a new instance of the EmployeeRepository class
public EmployeeRepository(AcmeDataContext dataContext) : IEmployeeRepository
Whenever a constructor is needed, the unity container resolves a connection, which is used to resolve a data context, then a repository, then a service, and finally the controller.
The issue is that IEmployeeRepository exposes the SubmitChanges method, since the service classes DO NOT have a DataContext reference.
I have been told that the unit of work should be managed from outside the repositories, so it would seem I ought to remove SubmitChanges from my repositories. Why is that?
If this is true, does this mean that I have to declare an IUnitOfWork interface and make every service class dependent upon it? How else can I allow my service classes to manage the unit of work?
You shouldn't try to supply the AcmeDataContext itself to the EmployeeRepository. I would even turn the whole thing around:
Define a factory that allows creating a new unit of work for the Acme domain:
Create an abstract AcmeUnitOfWork that abstracts away LINQ to SQL.
Create a concrete factory that can allows creating new LINQ to SQL unit of works.
Register that concrete factory in your DI configuration.
Implement an InMemoryAcmeUnitOfWork for unit testing.
Optionally implement convenient extension methods for common operations on your IQueryable<T> repositories.
UPDATE: I wrote a blog post on this subject: Faking your LINQ provider.
Below is a step-by-step with examples:
WARNING: This will be a loooong post.
Step 1: Defining the factory:
public interface IAcmeUnitOfWorkFactory
{
AcmeUnitOfWork CreateNew();
}
Creating a factory is important, because the DataContext implement IDisposable so you want to have ownership over the instance. While some frameworks allow you to dispose objects when not needed anymore, factories make this very explicit.
Step 2: Creating an abstract unit of work for the Acme domain:
public abstract class AcmeUnitOfWork : IDisposable
{
public IQueryable<Employee> Employees
{
[DebuggerStepThrough]
get { return this.GetRepository<Employee>(); }
}
public IQueryable<Order> Orders
{
[DebuggerStepThrough]
get { return this.GetRepository<Order>(); }
}
public abstract void Insert(object entity);
public abstract void Delete(object entity);
public abstract void SubmitChanges();
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected abstract IQueryable<T> GetRepository<T>()
where T : class;
protected virtual void Dispose(bool disposing) { }
}
There are some interesting things to note about this abstract class. The Unit of Work controls and creates the Repositories. A repository is basically something that implements IQueryable<T>. The repository implements properties that return a specific repository. This prevents users from calling uow.GetRepository<Employee>() and this creates a model that is very close to what you are already doing with LINQ to SQL or Entity Framework.
The unit of work implements Insert and Delete operations. In LINQ to SQL these operations are placed on the Table<T> classes, but when you try to implement it this way it will prevent you from abstracting LINQ to SQL away.
Step 3. Create a concrete factory:
public class LinqToSqlAcmeUnitOfWorkFactory : IAcmeUnitOfWorkFactory
{
private static readonly MappingSource Mapping =
new AttributeMappingSource();
public string AcmeConnectionString { get; set; }
public AcmeUnitOfWork CreateNew()
{
var context = new DataContext(this.AcmeConnectionString, Mapping);
return new LinqToSqlAcmeUnitOfWork(context);
}
}
The factory created a LinqToSqlAcmeUnitOfWork based on the AcmeUnitOfWork base class:
internal sealed class LinqToSqlAcmeUnitOfWork : AcmeUnitOfWork
{
private readonly DataContext db;
public LinqToSqlAcmeUnitOfWork(DataContext db) { this.db = db; }
public override void Insert(object entity)
{
if (entity == null) throw new ArgumentNullException("entity");
this.db.GetTable(entity.GetType()).InsertOnSubmit(entity);
}
public override void Delete(object entity)
{
if (entity == null) throw new ArgumentNullException("entity");
this.db.GetTable(entity.GetType()).DeleteOnSubmit(entity);
}
public override void SubmitChanges();
{
this.db.SubmitChanges();
}
protected override IQueryable<TEntity> GetRepository<TEntity>()
where TEntity : class
{
return this.db.GetTable<TEntity>();
}
protected override void Dispose(bool disposing) { this.db.Dispose(); }
}
Step 4: Register that concrete factory in your DI configuration.
You know self best how to register the IAcmeUnitOfWorkFactory interface to return an instance of the LinqToSqlAcmeUnitOfWorkFactory, but it would look something like this:
container.RegisterSingle<IAcmeUnitOfWorkFactory>(
new LinqToSqlAcmeUnitOfWorkFactory()
{
AcmeConnectionString =
AppSettings.ConnectionStrings["ACME"].ConnectionString
});
Now you can change the dependencies on the EmployeeService to use the IAcmeUnitOfWorkFactory:
public class EmployeeService : IEmployeeService
{
public EmployeeService(IAcmeUnitOfWorkFactory contextFactory) { ... }
public Employee[] GetAll()
{
using (var context = this.contextFactory.CreateNew())
{
// This just works like a real L2S DataObject.
return context.Employees.ToArray();
}
}
}
Note that you could even remove the IEmployeeService interface and let the controller use the EmployeeService directly. You don't need this interface for unit testing, because you can replace the unit of work during testing preventing the EmployeeService from accessing the database. This will probably also save you a lot of DI configuration, because most DI frameworks know how to instantiate a concrete class.
Step 5: Implement an InMemoryAcmeUnitOfWork for unit testing.
All these abstractions are there for a reason. Unit testing. Now let's create a AcmeUnitOfWork for unit testing purposes:
public class InMemoryAcmeUnitOfWork: AcmeUnitOfWork, IAcmeUnitOfWorkFactory
{
private readonly List<object> committed = new List<object>();
private readonly List<object> uncommittedInserts = new List<object>();
private readonly List<object> uncommittedDeletes = new List<object>();
// This is a dirty trick. This UoW is also it's own factory.
// This makes writing unit tests easier.
AcmeUnitOfWork IAcmeUnitOfWorkFactory.CreateNew() { return this; }
// Get a list with all committed objects of the requested type.
public IEnumerable<TEntity> Committed<TEntity>() where TEntity : class
{
return this.committed.OfType<TEntity>();
}
protected override IQueryable<TEntity> GetRepository<TEntity>()
{
// Only return committed objects. Same behavior as L2S and EF.
return this.committed.OfType<TEntity>().AsQueryable();
}
// Directly add an object to the 'database'. Useful during test setup.
public void AddCommitted(object entity)
{
this.committed.Add(entity);
}
public override void Insert(object entity)
{
this.uncommittedInserts.Add(entity);
}
public override void Delete(object entity)
{
if (!this.committed.Contains(entity))
Assert.Fail("Entity does not exist.");
this.uncommittedDeletes.Add(entity);
}
public override void SubmitChanges()
{
this.committed.AddRange(this.uncommittedInserts);
this.uncommittedInserts.Clear();
this.committed.RemoveAll(
e => this.uncommittedDeletes.Contains(e));
this.uncommittedDeletes.Clear();
}
protected override void Dispose(bool disposing)
{
}
}
You can use this class in your unit tests. For instance:
[TestMethod]
public void ControllerTest1()
{
// Arrange
var context = new InMemoryAcmeUnitOfWork();
var controller = new CreateValidController(context);
context.AddCommitted(new Employee()
{
Id = 6,
Name = ".NET Junkie"
});
// Act
controller.DoSomething();
// Assert
Assert.IsTrue(ExpectSomething);
}
private static EmployeeController CreateValidController(
IAcmeUnitOfWorkFactory factory)
{
return new EmployeeController(return new EmployeeService(factory));
}
Step 6: Optionally implement convenient extension methods:
Repositories are expected to have convenient methods such as GetById or GetByLastName. Of course IQueryable<T> is a generic interface and does not contains such methods. We could clutter our code with calls like context.Employees.Single(e => e.Id == employeeId), but that's really ugly. The perfect solution to this problem is: extension methods:
// Place this class in the same namespace as your LINQ to SQL entities.
public static class AcmeRepositoryExtensions
{
public static Employee GetById(this IQueryable<Employee> repository,int id)
{
return Single(repository.Where(entity => entity.Id == id), id);
}
public static Order GetById(this IQueryable<Order> repository, int id)
{
return Single(repository.Where(entity => entity.Id == id), id);
}
// This method allows reporting more descriptive error messages.
[DebuggerStepThrough]
private static TEntity Single<TEntity, TKey>(IQueryable<TEntity> query,
TKey key) where TEntity : class
{
try
{
return query.Single();
}
catch (Exception ex)
{
throw new InvalidOperationException("There was an error " +
"getting a single element of type " + typeof(TEntity)
.FullName + " with key '" + key + "'. " + ex.Message, ex);
}
}
}
With these extension methods in place, it allows you to call those GetById and other methods from your code:
var employee = context.Employees.GetById(employeeId);
What the nicest thing is about this code (I use it in production) is that -once in place- it saves you from writing a lot of code for unit testing. You will find yourself adding methods to the AcmeRepositoryExtensions class and properties to the AcmeUnitOfWork class when new entities are added to the system, but you don't need to create new repository classes for production or testing.
This model has of course some shortcomes. The most important perhaps is that LINQ to SQL isn't abstract away completely, because you still use the LINQ to SQL generated entities. Those entity contain EntitySet<T> properties which are specific to LINQ to SQL. I haven't found them to be in the way of proper unit testing, so for me it's not a problem. If you want you can always use POCO objects with LINQ to SQL.
Another shortcome is that complicated LINQ queries can succeed in test but fail in production, because of limitations (or bugs) in the query provider (especially the EF 3.5 query provider sucks). When you do not use this model, you are probably writing custom repository classes that are completely replaced by unit test versions and you will still have the problem of not being able to test queries to your database in unit tests. For this you will need integration tests, wrapped by a transaction.
A last shortcome of this design is the use of Insert and Delete methods on the Unit of Work. While moving them to the repository would force you to have a design with an specific class IRepository<T> : IQueryable<T> interface, it prevents you from other errors. In the solution I use myself I also have InsertAll(IEnumerable) and DeleteAll(IEnumerable) methods. It is however easy to mistype this and write something like context.Delete(context.Messages) (note the use of Delete instead of DeleteAll). This would compile fine, because Delete accepts an object. A design with delete operations on the repository would prevent such statement from compiling, because the repositories are typed.
UPDATE: I wrote a blog post on this subject that describes this solution in even more detail: Faking your LINQ provider.
I hope this helps.
If combining unit of work and repository patterns, some people advocate that UoW should be managed outside of repository so that you could create two repositories (say, CustomerRepository and OrderRepository) and pass them the same UoW instance ensuring that all the changes to the DB will be done atomically when you finally call UoW.Complete().
In a mature DDD solution however, there should not be need for both UoW and a repository. This is because is such a solution aggregate boundaries are defined is such a way, that there is no need of atomic changes involving more than one repository.
Does this answer your question?
I'm trying to call ObjectContext.ExecuteFunction from my objectcontext object in the repository of my site.
The repository is generic, so all I have is an ObjectContext object, rather than one that actually represents my specific one from the Entity Framework.
Here's an example of code that was generated that uses the ExecuteFunction method:
[global::System.CodeDom.Compiler.GeneratedCode("System.Data.Entity.Design.EntityClassGenerator", "4.0.0.0")]
public global::System.Data.Objects.ObjectResult<ArtistSearchVariation> FindSearchVariation(string source)
{
global::System.Data.Objects.ObjectParameter sourceParameter;
if ((source != null))
{
sourceParameter = new global::System.Data.Objects.ObjectParameter("Source", source);
}
else
{
sourceParameter = new global::System.Data.Objects.ObjectParameter("Source", typeof(string));
}
return base.ExecuteFunction<ArtistSearchVariation>("FindSearchVariation", sourceParameter);
}
But what I would like to do is something like this...
public class Repository<E, C> : IRepository<E, C>, IDisposable
where E : EntityObject
where C : ObjectContext
{
private readonly C _ctx;
// ...
public ObjectResult<E> ExecuteFunction(string functionName, params[])
{
// Create object parameters
return _ctx.ExecuteFunction<E>(functionName, /* parameters */)
}
}
Anyone know why I have to call ExecuteFunction from base instead of _ctx?
Also, is there any way to do something like I've written out? I would really like to keep my repository generic, but with having to execute stored procedures it's looking more and more difficult...
Update: Here's what I've tried and the method does not show up in intellisense/it gives me an error when I try to compile with it
public ArtistSearchVariation findSearchVariation(string source)
{
System.Data.Objects.ObjextContext _ctx = new ObjectContext(/* connection string */);
System.Data.Objects.ObjectParameter sourceParam = new ObjectParameter("Source", source);
return _ctx.ExecuteFunction<ArtistSearchVariation>("FindSearchVariation", sourceParam);
}
Thanks,
Matt
You don't have to use base.ExecuteFunction, the ExecuteFunction method (and overloads) are public, not protected, so you can call them from external sites. Are you having trouble calling it?