Unit Testing Queries that passes Expression<Func<T,bool>> to Repository - c#

I'm having an issue really testing the Querying side of my architecture where I'm calling into a repository that expects an Expression<Func<T, bool>> as parameter for filtering. I was trying to understand this article, where Mark is saying to use Stubs for queries instead.
Lets say I have a query handler:
public class GetUserByEmailQueryHandler : IQueryHandler<GetUserByEmailQuery, User>
{
private readonly IGenericRepository<User> userRepository;
public GetUserByEmailQueryHandler(IGenericRepository<User> userRepository)
{
this.userRepository = userRepository;
}
public User Handle(GetUserByEmailQuery query)
{
return this.userRepository.Find(u => u.Email == query.Email && u.IsLockedOut == false);
}
}
Now my test is going to look something like this:
[Fact]
public void Correctly_Returns_Result()
{
// arrange
var id = Guid.NewGuid();
var email = "test#test.com";
var userRepositoryMock = new Mock<IGenericRepository<User>>();
userRepositoryMock.Setup(
r =>
r.Find(It.IsAny<Expression<Func<User, bool>>>())).Returns(new User { UserId = id }).Verifiable();
// Act
var query = new GetUserByEmailQuery(email);
var queryHandler = new GetUserByEmailQueryHandler(userRepositoryMock.Object);
var item = queryHandler.Handle(query);
// Assert
userRepositoryMock.Verify();
Assert.Equal(id, item.UserId);
}
To me, this test is useless, especially using It.IsAny<Expression<Func<User, bool>>>() as I could be filtering by anything at all. The filter would be a crucial business logic that needs to be tested. How can I test an expression like this? Is this one of those reasons why a generic repository is bad and I should use a specific repository that take exactly the filter parameters that is needed? If that is the case, I'll be moving the expression from one layer to the other and I'd still need to test it
If I should use stubs as Mark said in his blog, are there any examples out there? Am I supposed to run this query on an in-memory list which will be used to validate that the filter expression is correct?

Is this one of those reasons why a generic repository is bad
Yes, it is. Additionally, if you want to follow the SOLID principles of OOD (not that you must, but they are often useful in order to understand the consequences of design decisions), "clients […] own the abstract interfaces" (Agile Principles, Patterns, and Practices, chapter 11). Thus, the interface used by the client should be defined in terms of what the client needs, not by what some general-purpose library exposes.
In this particular case, it looks like what the GetUserByEmailQueryHandler really needs is an ability to query based on an email address, so you could define a reader interface like this:
public interface IUserReader
{
User FindByEmail(string email);
}
This turns GetUserByEmailQueryHandler into something like this:
public class GetUserByEmailQueryHandler : IQueryHandler<GetUserByEmailQuery, User>
{
private readonly IUserReader userRepository;
public GetUserByEmailQueryHandler(IUserReader userRepository)
{
this.userRepository = userRepository;
}
public User Handle(GetUserByEmailQuery query)
{
return this.userRepository.FindByEmail(query.Email);
}
}
At this point, the GetUserByEmailQueryHandler class is so degenerate that you should seriously consider whether it adds any value.
The filter would be a crucial business logic that needs to be tested. How can I test an expression like this?
That really depends on where you want that business logic to execute in the final system. You could test a filter by running it in memory, but if you ultimately plan on executing it on a database server, you'll have to involve the database in your automated tests. That tends to suck, which is the case why most programmers are seriously looking for alternatives to relational databases.
Sorry, but if there's a solution to this particular problem, I don't know what it is.
Personally, I design my system so that they don't rely on complicated filter expressions, but only on simple filter expressions that I can treat as Humble Objects.

To me, this test is useless, especially using
It.IsAny<Expression<Func<User, bool>>>() as I could be filtering by
anything at all. The filter would be a crucial business logic that
needs to be tested. How can I test an expression like this?
No matter what abstraction is used it is needed to test filtering business logic. I answered the similar SO question "Why this mock with Expression is not matching?" a year ago and you can use a code example from it.
In order to test filtering business logic for your design I would change your code the following way:
[Fact]
public void Correctly_Returns_Result()
{
// Arrange
var validEmail = "test#test.com";
var userThatMatches = new User { UserId = Guid.NewGuid(), Email = validEmail, IsLockedOut = false };
var userThatDoesnotMatchByIsLockedOut = new User { UserId = Guid.NewGuid(), Email = validEmail, IsLockedOut = false };
var userThatDoesnotMatchByEmail = new User { UserId = Guid.NewGuid(), Email = "Wrong Email", IsLockedOut = true };
var aCollectionOfUsers = new List<User>
{
userThatMatches,
userThatDoesnotMatchByIsLockedOut,
userThatDoesnotMatchByEmail
};
var userRepositoryMock = new Mock<IGenericRepository<User>>();
userRepositoryMock
.Setup(it => it.Find(It.IsAny<Expression<Func<User, bool>>>()))
.Returns<Expression<Func<User, bool>>>(predicate =>
{
return aCollectionOfUsers.Find(user => predicate.Compile()(user));
});
var sut = new GetUserByEmailQueryHandler(
userRepositoryMock.Object);
// Act
var foundUser = sut.Handle(new GetUserByEmailQuery(validEmail));
// Assert
userRepositoryMock.Verify();
Assert.Equal(userThatMatches.UserId, foundUser.UserId);
}
You can use Return method which allows you to access passed expression and apply it to any target collection of users.

Related

Approach to generate Random specimen based on Customization

I want to be able to generate distinct values based on a ICustomization using ISpecimenBuilder.CreateMany. I was wondering what would be the best solution since AutoFixture will generate the same values for all entities.
public class FooCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
var specimen = fixture.Build<Foo>()
.OmitAutoProperties()
.With(x => x.CreationDate, DateTime.Now)
.With(x => x.Identifier, Guid.NewGuid().ToString().Substring(0, 6)) // Should gen distinct values
.With(x => x.Mail, $"contactme#mail.com")
.With(x => x.Code) // Should gen distinct values
.Create();
fixture.Register(() => specimen);
}
}
I've read this and that might be what I'm looking for. This approach has many drawbacks though: First it seems really counter intuitive to call Create<List<Foo>>() because it kinda of defeats the purpose of what to expect from CreateMany<Foo>; that would generate a hardcoded sized List<List<Foo>> (?). Another drawback is that I'd have to have two customizations for each entity; one to create custom collections and another one to create a single instance, since we are overriding the behaviour of Create<T> to create a collections.
PS.: The main goal is to reduce the amount of code on my tests, so I must avoid calling With() to customize the values for every test. Is there a proper way of doing this?
In general, a question like this triggers some alarm bells with me, but I'll give an answer first, and then save the admonitions till the end.
If you want distinct values, relying on randomness wouldn't be my first choice. The problem with randomness is that sometimes, a random process will pick (or produce) the same value twice in a row. Obviously, this depends on the range from which one wants to pick, but even if we consider that something like Guid.NewGuid().ToString().Substring(0, 6)) would be sufficiently unique for our use case, someone could come by later and change it to Guid.NewGuid().ToString().Substring(0, 3)) because it turned out that requirements changed.
Then again, relying on Guid.NewGuid() is good enough to ensure uniqueness...
If I interpret the situation here correctly, though, Identifier must be a short string, which means that you can't use Guid.NewGuid().
In such cases, I'd rather guarantee uniqueness by creating a pool of values from which you can draw:
public class RandomPool<T>
{
private readonly Random rnd;
private readonly List<T> items;
public RandomPool(params T[] items)
{
this.rnd = new Random();
this.items = items.ToList();
}
public T Draw()
{
if (!this.items.Any())
throw new InvalidOperationException("Pool is empty.");
var idx = this.rnd.Next(this.items.Count);
var item = this.items[idx];
this.items.RemoveAt(idx);
return item;
}
}
This generic class is just a proof of concept. If you wish to draw from a big pool, having to initialise it with, say, millions of values could be inefficient, but in that case, you could change the implementation so that the object starts with an empty list of values, and then add each randomly generated value to a list of 'used' objects each time Draw is called.
To create unique identifiers for Foo, you can customise AutoFixture. There's many ways to do this, but here's a way using an ISpecimenBuilder:
public class UniqueIdentifierBuilder : ISpecimenBuilder
{
private readonly RandomPool<string> pool;
public UniqueIdentifierBuilder()
{
this.pool = new RandomPool<string>("foo", "bar", "baz", "cux");
}
public object Create(object request, ISpecimenContext context)
{
var pi = request as PropertyInfo;
if (pi == null || pi.PropertyType != typeof(string) || pi.Name != "Identifier")
return new NoSpecimen();
return this.pool.Draw();
}
}
Add this to a Fixture object, and it'll create Foo objects with unique Identifier properties until the pool runs dry:
[Fact]
public void CreateTwoFooObjectsWithDistinctIdentifiers()
{
var fixture = new Fixture();
fixture.Customizations.Add(new UniqueIdentifierBuilder());
var f1 = fixture.Create<Foo>();
var f2 = fixture.Create<Foo>();
Assert.NotEqual(f1.Identifier, f2.Identifier);
}
[Fact]
public void CreateManyFooObjectsWithDistinctIdentifiers()
{
var fixture = new Fixture();
fixture.Customizations.Add(new UniqueIdentifierBuilder());
var foos = fixture.CreateMany<Foo>();
Assert.Equal(
foos.Select(f => f.Identifier).Distinct(),
foos.Select(f => f.Identifier));
}
[Fact]
public void CreateListOfFooObjectsWithDistinctIdentifiers()
{
var fixture = new Fixture();
fixture.Customizations.Add(new UniqueIdentifierBuilder());
var foos = fixture.Create<IEnumerable<Foo>>();
Assert.Equal(
foos.Select(f => f.Identifier).Distinct(),
foos.Select(f => f.Identifier));
}
All three tests pass.
All that said, though, I wish to add some words of caution. I don't know what your particular scenario is, but I'm also writing these warnings to other readers who may happen by this answer at a later date.
What's the motivation for wanting unique values?
There can be several, and I can only speculate. Sometimes, you need values to be truly unique, for example when you're modelling domain Entities, and you need each Entity to have a unique ID. In cases like that, I think this is something that should be modelled by the Domain Model, and not by a test utility library like AutoFixture. The easiest way to ensure uniqueness is to just use GUIDs.
Sometimes, uniqueness isn't a concern of the Domain Model, but rather of one or more test cases. That's fair enough, but I don't think it makes sense to universally and implicitly enforce uniqueness across all unit tests.
I believe that explicit is better than implicit, so in such cases, I'd rather prefer to have an explicit test utility method that would allow one to write something like this:
var foos = fixture.CreateMany<Foo>();
fixture.MakeIdentifiersUnique(foos);
// ...
This would allow you to apply the uniqueness constraints to those unit tests that require them, and not apply them where they're irrelevant.
In my experience, one should only add Customizations to AutoFixture if those Customizations make sense across a majority of the tests in a test suite. If you add Customizations to all tests just to support a test case for one or two tests, you could easily get brittle and unmaintainable tests.

Entity Framework 6 Unit Testing (NSubstitute) - How to test that an object with children does not return children when children are not requested

I have a method to get an Employer using an Entity Framework context (Lazy Loading is disabled). Sometimes I want the Employees included, sometimes I don't so I have the following code in my data access class:
public Employer GetEmployer(int employerId, bool includeRelationships)
{
Employer employer;
if (includeRelationships)
{
employer = (from e in this.context.Employers.Include(e => e.Employees)
where e.EmployerId == employerId
select e).SingleOrDefault();
}
else
{
employer = this.context.Employers.SingleOrDefault(e => e.EmployerId == employerId);
}
return employer;
}
From several questions about how to use NSubstitute to substitute EF context returns I have this extension method in my test project to hook up the DbSet calls for substitution (specifically NSubstitute DbSet / IQueryable<T>):
public static IDbSet<T> Initialise<T>(this IDbSet<T> dbSet, IQueryable<T> data) where T : class
{
dbSet.Provider.Returns(data.Provider);
dbSet.Expression.Returns(data.Expression);
dbSet.ElementType.Returns(data.ElementType);
dbSet.GetEnumerator().Returns(data.GetEnumerator());
return dbSet;
}
This is then used to initialise a substitute set of Employers in the test class:
[TestInitialize]
public void TestInitialise()
{
this.context = Substitute.For<EmployerContext>();
this.dao = new EmployerDao(this.context);
var employers = new List<Employer>();
var employerWithoutEmployee = new Employer { EmployerId = 1 };
employers.Add(employerWithoutEmployee);
var employerWithEmployee = new Employer { EmployerId = 2 };
var employee = new Employee { EmployeeId = 1, EmployerId = 2, Employer = employerWithEmployee };
employerWithEmployee.Employees.Add(employee);
employers.Add(employerWithEmployee);
this.substituteEmployers = Substitute.For<IDbSet<Employer>>().Initialise(employers.AsQueryable());
this.context.Employers.Returns(this.substituteEmployers);
}
So, I now have a test that looks like this:
[TestMethod]
public void ReturnsEmployerWithNullEmployeeWhenIncludeIsFalse()
{
// Assemble
var expectedEmployer = this.substituteEmployers.First(e => e.Employees.Any();
var employerId = expectedEmployer.EmployerId;
// Act
var actualEmployer = this.dao.GetEmployer(employerId, false);
var actualEmployee = actualEmployer.Employees.FirstOrDefault();
// Assert
Assert.AreSame(expectedEmployer, actualEmployer);
Assert.IsNotNull(actualEmployer);
Assert.IsNull(actualEmployee);
this.context.Employers.ReceivedWithAnyArgs();
}
This test is failing on Assert.IsNull(actualEmployee);
In real usage, GetEmployer will return an Employer with no Employee children.
However, because I am substituting an Employer with Employee (because this is what I am testing!) the method is returning the substitute which has an Employee.
How can I test this?
Or, am I testing incorrectly?
Should I instead use the Employer which doesn't have an Employee, because that is what the context would return?
But then doesn't that make the test pointless!?!
I'm thinking myself in circles here...
Many times I have tried to mock out DbContext with different techniques. But every time when I thought "yeah, this time it behaves like real EF!" I have found yet another use-case when mock does not behave like a real thing. An having tests that pass with mocks does give you a false confidence. But when the same actions happen in production, you get exceptions and errors.
So my conclusion was to stop trying to mock DbContext and just do integration tests. It is a bit problematic to set up, but setting up realistic mock takes even more time! And I've written about how to have trouble-free integration tests in my blog: http://tech.trailmax.info/2014/03/how-we-do-database-integration-tests-with-entity-framework-migrations/
Now I tend to write a lot of integration tests (for CRUD stuff) that actually go into DB and mess about. Gives you much more assurance (rather than using db-mock) that the same actions will work in production.
Not really an answer to your question. Just my .02$
This is not possible. It is a limitation of the EF "in-memory" testing model. See this article for details:
https://msdn.microsoft.com/en-us/data/dn314429#limitations

Moq: Setting Up Method That Compares Guids Inside A Lambda Expression Fails

This seems like a very simple task but I find it extremely hard to accomplish in Moq. I have a repository that calls a unit of work to query a random picture from a database. This query has one constraint; the random picture from the database cannot be equal to the current picture being displayed. I'm building an NUnit test for the repository and I'd like to mock the unit of work like so:
[TestFixture]
public class When_the_next_random_picture_for_TopSlidePicture_show_has_been_requested
{
private Guid _currentPictureID;
private Picture _randomPicture;
private Mock<IUnitOfWork<Guid>> _unitOfWorkMock;
[SetUp]
public void Context()
{
_currentPictureID = Guid.NewGuid();
_randomPicture = new Picture { ID = Guid.NewGuid() };
_unitOfWorkMock = new Mock<IUnitOfWork<Guid>>();
//TODO: Find out how to setup and verify expression when mocking method with equality comparison in a lambda expression.
_unitOfWorkMock.Setup(uow => uow.GetRandom<Picture>(pic => pic.ID != _currentPictureID))
.Returns(_randomPicture);
}
[Test]
public void The_PictureRepository_can_query_next_random_picture()
{
//Arrange
var picRepo = new PictureRepository(_unitOfWorkMock.Object);
//Act
var randomPicture = picRepo.GetNextRandomPicture(_currentPictureID);
//Assert
_unitOfWorkMock.Verify(uow =>
uow.GetRandom<Picture>(pic => pic.ID != _currentPictureID)
, Times.Once());
Assert.AreEqual(_randomPicture, randomPicture);
}
}
In the code above, the GetRandom<Picture>(Expression<Func<Picture, bool>>) in the UnitOfWork is supposed to return any picture in the database who's Guid ID isn't equal to the current pics ID. However, Setup() method called from _unitOfWorkMock returns null regardless of _randomPicture's value. After much research I found the following procedure:
_unitOfWorkMock = new Mock<IUnitOfWork<Guid>>();
_unitOfWorkMock.Setup(uow => uow.GetRandom<Picture>(It.IsAny<Expression<Func<Picture, bool>>>()))
.Returns(_randomPicture);
var randomPicture = picRepo.GetNextRandomPicture(_currentPictureID);
//Assert
_unitOfWorkMock.Verify(uow =>
uow.GetRandom<Picture>(It.IsAny<Expression<Func<Picture, bool>>>())
, Times.Once());
This allows the test to pass. BUT, I didn't test whether the picture returned from the db has the same Guid ID of the current picture ID passed in; which is the key principle for even building the test!!!
I love the Moq framework and prefer it over all other testing tools, but this seems like a massive breach of integrity as far as a unit testing platform goes. Please, someone, inform me on what I'm not seeing clearly and show me a simple and easy way to accomplish this seemingly simple task!
Gratitude
UPDATE
Thanks to #StriplingWarrior, I was able to solve the problem! His boolean algebra was wrong, but his answer was sound ;-) I found these modifications to my above code to work:
_unitOfWorkMock = new Mock<IUnitOfWork<Guid>>();
_unitOfWorkMock.Setup(uow => uow.GetRandom<Picture>(It.Is<Expression<Func<Picture, bool>>>(e => TestIdMatchExpression(e))))
.Returns(_randomPicture);
private bool TestIdMatchExpression(Expression<Func<Picture, bool>> expr)
{
var func = expr.Compile();
Assert.IsFalse(func(new Picture { ID = _referencePictureID }));
return true;
}
//Assert
_unitOfWorkMock.Verify(uow =>
uow.GetRandom<Picture>(It.Is<Expression<Func<Picture, bool>>>(e => TestIdMatchExpression(e)))
, Times.Once());
Thanks again #StriplingWarrior!
You should be able to use a special overload of It.Is<>() to test the expression:
It.Is<Expression<Func<Picture, bool>>>(e => TestIdMatchExpression(e))
From there you just have to figure out the best way to check the expression that gets passed in. The easiest way is probably to test the behavior: the expression should match a picture with the same guid, and reject a picture with a different one.
bool TestIdMatchExpression(Expression<Func<Picture, bool>> expr)
{
var func = expr.Compile();
Assert.IsTrue(func(new Picture{ID = _currentPictureID}));
Assert.IsFalse(func(new Picture{ID = Guid.NewGuid()}));
}
Remember, when you do unit testing of a method, you have to isolate that test, mock every external dependency including database in your case , do the test of that method for different conditions of the external dependencies
Picture randomPictureExpected = new Picture{ ID=Guid.NewGuid()};
_unitOfWorkMock.Setup(uow => uow.GetRandom<Picture>(pic=>pic.ID!=_currentPictureID))
.Returns(randomPictureExpected);
and your assert would be like
var randomPictureActual = picRepo.GetNextRandomPicture(_currentPictureID);
Assert.AreEqual (randomPictureExpected.ID, randomPictureActual.ID);

How can an IRepository be unit tested?

I have written the following method using the Repository mentioned
in the following blog-post (http://www.codecapers.com/post/Using-RavenDB-with-ASPNET-MVC.aspx) using RavenDB:
public User GetUserById(string id)
{
var user = (from usr in _repository.All<User>() where usr.Id == id select usr).FirstOrDefault();
if (user == null)
{
throw new NullReferenceException("No user with the id (" + id + ") could be found.");
}
return user;
}
How would you unit test this method with nunit (and perhaps moq)?
"user" is just a normal class.
Usualy you don't write tests directly against the repository layer.
Say for example you are using nHibernate or Entity Framework, than wirting tests against the repository would technically be testing that framework.
The creators or those ORMs already done that.
Also talking to a database makes your test an integration test not a unit test.
Your unit test would be for example against the business layer mocking out the repository layer.
If you want to write an integration test you also write that against the business layer but don't mock the repository layer and let it go through.
I would do the following to prepare your code:
Make sure your _repository is being passed in through a constructor or property, so that it can be easily changed for tests.
Make sure your _repository variable is declared as the IRepository type, rather than the concrete type.
Then, in your tests:
Create a mock of your interface and pass this in to be your _repository.
Override the .All<User>() method to return a known, hardcoded list of User with suitable values for your tests.
Assert in one test that the correct value is returned when you query an existing ID.
Assert in a separate test that the exception is thrown when you query a non-existant ID.
The first question is going to be - what are you testing in this context? The method provided really only has two outcomes, so you're basically testing whether user is null or not. Is that a value added test?
As for the how, Im assuming _repository is injected via some mechanism? If so, then you simply provide a Mock<IRepository> (insert your type name as appropriate) and inject that in the place of _repository wherever that is injected. Then you can setup the return values and test your method for the exception or not.
mockRepository.Setup(x => x.All<User>()).Returns(new List<User> { ... });
RavenDB is specifically designed so that you don't need to mock everything for unit testing.
Just run it in-memory and you can then perform you unit tests against it directly. See this blog post for more info.
It lets you write code like this:
[Fact]
public void CanQueryForDistinctItemsUsingLinq()
{
using (var store = NewDocumentStore())
{
using (var s = store.OpenSession())
{
s.Store(new { Name = "ayende" });
s.Store(new { Name = "ayende" });
s.Store(new { Name = "rahien" });
s.SaveChanges();
}
store.DocumentDatabase.PutIndex("test", new IndexDefinition
{
Map = "from doc in docs select new { doc.Name }",
Stores = { { "Name", FieldStorage.Yes } }
});
using (var s = store.OpenSession())
{
var objects = s.Query<User>("test")
.Customize(x => x.WaitForNonStaleResults())
.Select(o => new {o.Name })
.Distinct()
.ToList();
Assert.Equal(2, objects.Count);
Assert.Equal("ayende", objects[0].Name);
Assert.Equal("rahien", objects[1].Name);
}
}
}
This comes from RavenDB unit/integration tests, so you'll need some infasctucture to get it working, but it gives the general idea.

How to create a generic method out of two similar yet different methods?

I have two similar methods that basically does the same thing only with different objects.
What's the best way to make a generic method out of this if possible?
The two objects:
public class StoreObject {
int Key;
string Address;
string Country;
int Latitude;
int Longitude;
}
public class ProjectObject {
int ProjectKey;
string Address;
string Description;
}
The two methods that I potentially want to make into a generic:
public StoreObject GetStoreByKey(int key)
{
using (DBEntities dbe = new DBEntities())
{
StoreObject so = new StoreObject();
var storeObject = (from s in dbe.StoreTables
where s.Key == key
select s).First();
so.Key = storeObject.key;
so.Address = storeObject.address;
so.Country = storeObject.country;
so.Latitude = storeObject.latitude;
so.Longitude = storeObject.longitude;
return so;
}
}
public ProjectObject GetProjectByKey(int projectKey)
{
using (DBEntities dbe = new DBEntities())
{
ProjectObject po = new ProjectObject();
var projectObject = (from p in dbe.ProjectTables
where p.ProjectKey == projectKey
select p).First();
po.Key = projectObject.p_key;
po.Address = projectObject.p_address;
po.Description = projectObject.p_description;
return po;
}
}
I must note that:
- I have no control over how the table fields are named (ie. p_description).
- StoreTable in the DB, for example, may have other properties (like telephone, postal code, etc) but I'm only interested in showing what I've shown in the code.
- The same goes for the ProjectTable.
Well, the tricky part is that your entities have different properties, so using generics to populate the different properties within one method will not be worth it. But you can return the whole object and then just use the properties you are interested in.
public T GetEntityByKey<T>(int key)
{
using (DBEntities dbe = new DBEntities())
{
return = dbe.StoreTables.Set<T>.Find(new object[] {key});
}
}
And to use it
StoreObject so = GetEntityByKey<StoreObject>(123);
if(so != null)
{
int lat = so.Latitude;
}
You can indeed abstract out the type returned, and factor the using, but for the rest you'd need either a switch on the type requested or, reflection to pass in the fields to retrieve as parameters and the DB query to use.
The former would be bad practice and brings little to the equation, and the latter is costly and can get messy.
This is not really a good candidate for generics, unless you have many of such look-alike methods, in which case I'd go for the reflection approach.
HTH,
Bab.
It's very unlikely that this is your entire 'unit of work' and thus the use of a fresh DBEntities() context in each of these methods is probably the root of your problem here.
Creating a Repository class that includes an instance of the DBEntities class for a single web request (or whatever other unit of request you have in your application) and which has these methods in it would be a better approach to eliminating the duplicate code here. The scope of the using() is then outside these methods and hopefully tied to your web request or other unit of time.
As an option instead of creating a new class you could also extend the DBEntities partial class to include methods like these (assuming this is generated code).
You essentially have two different functionalities in each method:
Query an entity
Map that entity to another type
The first part has been addressed by Steve Mallory.
For the second part, you can use a mapper framework to handle copying values from one instance to another. Since the names of each type do not match, you'll need to tell it how to map names (in your example, adding "p_" and making it lowercase). One possibility would be Emit Mapper.
If you were to factor out all commonality, it would be something like:
public TResult GetById<TResult, TEntity>(int id)
{
using (DBEntities dbe = new DBEntities())
{
T result = dbe.StoreTables.Set<T>.Find(new object[] {key});
var mapper = ObjectMapperManager.DefaultInstance
.GetMapper<TEntity, TResult>(
new DefaultMapConfig().MatchMembers((m1, m2) => "p_" + m1.ToLower() == m2));
return mapper.Map(result);
}
}

Categories

Resources