I have a Trait which I include in a number of classes to automatically set the id of 'creator' or updater. I do this using the static methods creating and updating in the trait boot method.
During seeding the seeder fails with:
Segmentation fault (core dumped)
This error relates to recursion / infinite loops if I understood other posts.
I know the issue is in the boot method of the trait but I have not figured out why / how to fix it. If I comment it out, seeds fine but the ids are not set.
My trait GlobalMethods boot method is:
protected static function bootGlobalMethods() {
parent::boot();
static::creating(function ($obj) {
$obj->creator_id = Auth::user()->id;
});
static::updating(function ($obj) {
$obj->updater_id = Auth::user()->id;
});
}
What have I missed? Thanks.
The culprit was:
parent::boot();
Removed it and works.
Related
I want to trigger my aspect for classes annotated with repositories and belonging to my packages, for example this one:
//com.foo.myapp.bar.repositories.dao
#Repository
public class MyRepo extends JpaRepository<MyEntity, String>{
My classes are jpa repositories created like this:
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "firstManagerFactory",
transactionManagerRef = "firstTransactionManager",
basePackages = {"com.foo.myapp.bar.repositories.first.dao"}
)
public class DbConfig {
My aspect is the following but only activates if I leave the repository() pointcut, but if I also specify application packages it doesn't work:
#Pointcut("within(#org.springframework.stereotype.Repository *)")
private void repositoryInvocation() {
// Method is empty as this is just a Pointcut, the implementations are in the advices.
}
#Pointcut("within(com.foo.myapp..*)")
public void applicationPackage() {
// Method is empty as this is just a Pointcut, the implementations are in the advices.
}
#Around("repositoryInvocation() && applicationPackage()") //this && doesn't work, I have to remove the second one
public Object aspectTriggers(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = joinPoint.proceed();
return result;
}
What am I missing?
edit:
I think I got it: problem is that the implementation of the repository does not belong to my application package, but to spring's SimpleJPARepository. It's like the aspect is only working on the implementation, totally ignoring the interface.
I think you do not want
#Pointcut("within(#org.springframework.stereotype.Repository *)")
but rather
#Pointcut("#within(org.springframework.stereotype.Repository)")
Be careful with your pointcut syntax, the two are not the same:
within() describes a package or class name you want to scope/limit your pointcut to.
#within() looks for a type (class) with the given annotation.
You want the latter, not the former.
Edit: On a second thought, actually I see no obvious reason why the first version should not work, even though it is a bit more complicated than the second.
But you said that you had problems with the second pointcut anyway. Are you 100% sure that your repository class really is in a com.foo.myapp (sub) package? No typo in either the package name or the pointcut? Actually, without trying and only looking at it, it should work otherwise.
I have a bunch of test where I use the new UseInMemory function in EF7. When I run them all some of them fail. When I run them single they all pass.
My best guess it is a conflict in EF7 because of the fact that every test runs in its own thread and they all kind of using the same DbContext class.
Here one of my Tests:
[Fact]
public void Index()
{
DbContextOptionsBuilder<DatabaseContext> optionsBuilder = new DbContextOptionsBuilder<DatabaseContext>();
optionsBuilder.UseInMemoryDatabase();
db = new DatabaseContext(optionsBuilder.Options);
AdminController controller = new AdminController(db);
var result = controller.Index() as ViewResult;
Assert.Equal("Index", result.ViewName);
}
I remake the dbContext object in every test but it seem not to make any different.
Would be greatful for any input. Thanks :)
The problem is, that the memory storage in InMemoryDatabase is registered as Singleton so you actually share the data between DbContexts even you think you don't.
You have to create your DbContexts like this:
public abstract class UnitTestsBase
{
protected static T GetNewDbContext<T>() where T : DbContext
{
var services = new ServiceCollection();
services
.AddEntityFramework()
.AddInMemoryDatabase()
.AddDbContext<T>(options => options.UseInMemoryDatabase());
var serviceProvider = services.BuildServiceProvider();
var dbContext = serviceProvider.GetRequiredService<T>();
dbContext.Database.EnsureDeleted();
return dbContext;
}
}
var newTestDbContext = GetNewDbContext<TestDbContext>()
I also was led to beleive that .UseInMemoryDatabase() has no persistence, but that does not seem to be the case (at least with the latest versions)!
As noted in How can I reset an EF7 InMemory provider between unit tests? you want to do a db.Database.EnsureDeleted() BUT I also noticed that this does NOT reset auto increment ids.
In Entity framework, I have implemented generic repository and unit of work pattern.
Below is related stuff from unit of work:
public IRepository<TEntity, TKey> GetRepository<TEntity, TKey>() where TEntity : class
{
if (_repositories == null)
{
_repositories = new Dictionary<string, object>();
}
string key = String.Format("{0}|{1}", typeof(TEntity).Name, typeof(TKey).Name);
if (_repositories.ContainsKey(key))
{
return (IRepository<TEntity, TKey>)_repositories[key];
}
Type repositoryType = typeof(Repository<TEntity, TKey>);
_repositories.Add(key, Activator.CreateInstance(repositoryType, _dataContext));
return (IRepository<TEntity, TKey>)_repositories[key];
}
From Manager layer, entity framework is call as below:
IRepository<tablenameEntity int> _tableEntityRepository = _unitOfWork.GetRepository<tablenameEntity, int>();
Error is as follow:
An error occurred while starting a transaction on the provider connection. See the inner exception for details.
{"New transaction is not allowed because there are other threads running in the session."}.
Actually, I just did as below,
remove stored procedure and function from model browser and added procedure and function again.
run custom tool on edmx file.
It just work out.
I am not sure, what was the issue. did that before also, but it was not work.. now, it works and not produce after that.
Thanks
By leveraging the Testing with async queries section of the Testing with a Mocking Framework article on MSDN, I've been able to create many successfully passing tests.
Here's my test code, which uses NSubstitute for mocks:
var dummyQueryable = locations.AsQueryable();
var mock = Substitute.For<DbSet<Location>, IDbAsyncEnumerable<Location>, IQueryable<Location>>();
((IDbAsyncEnumerable<Location>)mock).GetAsyncEnumerator().Returns(new TestDbAsyncEnumerator<Location>(dummyQueryable.GetEnumerator()));
((IQueryable<Location>)mock).Provider.Returns(new TestDbAsyncQueryProvider<Location>(dummyQueryable.Provider));
((IQueryable<Location>)mock).Expression.Returns(dummyQueryable.Expression);
((IQueryable<Location>)mock).ElementType.Returns(dummyQueryable.ElementType);
((IQueryable<Location>)mock).GetEnumerator().Returns(dummyQueryable.GetEnumerator());
sut.DataContext.Locations = mock;
var result = await sut.Index();
result.Should().BeView();
sut.Index() doesn't do much, but it makes the following query:
await DataContext.Locations
.GroupBy(l => l.Area)
.ToListAsync());
This works fine until I add a projection into the query:
await DataContext.Locations
.GroupBy(l => l.Area)
.Select(l => new LocationsIndexVM{ Area = l.Key }) // added projection
.ToListAsync());
which results in this exception:
System.InvalidOperationException
The source IQueryable doesn't implement IDbAsyncEnumerable<LocationsIndexVM>. Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations. For more details see http://go.microsoft.com/fwlink/?LinkId=287068.
at System.Data.Entity.QueryableExtensions.AsDbAsyncEnumerable(IQueryable`1 source)
at System.Data.Entity.QueryableExtensions.ToListAsync(IQueryable`1 source)
at Example.Web.Controllers.HomeController.<Index>d__0.MoveNext() in HomeController.cs: line 25
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Example.Test.Web.Controllers.HomeControllerShould.<TempTest>d__4.MoveNext() in HomeControllerShould.cs: line 71
UPDATE: I've uploaded a small, simple solution that reproduces this problem.
Can anyone provide an example of what is required to unit test a query that is both async and contains a .Select() projection?
So I did a bit of digging, and the issue is to do with the way the TestDbAsyncEnumerable<T> exposes the IQueryProvider. My best guess as to the reasoning is below, and the solution below that.
TestDbAsyncEnumerable<T> inherits from EnumerableQuery<T>, which in turn inherits from IQueryable<T>, and explicitly implements the Provider property of this interface:
IQueryProvider IQueryable.Provider { get ... }
Given that it's implemented explicitly, I am assuming that the LINQ internals explicitly cast a type before trying to get the Provider:
((IQueryable<T>)source).Provider.CreateQuery(...);
I don't have a source on hand (and can't be bothered looking for one), but I believe the type binding rules are different for explicit implementations; essentially, the Provider property on your TestDbAsyncEnumerable<T> is not considered to be an implementation of IQueryable<T>.Provider as an explicit one exists further up the chain, so your TestDbAsyncQueryProvider<T> is never returned.
The fix for this is to make TestDbAsyncEnumerable<T> also inherit IQueryable<T> and explicitly implement the Provider property, as below (adjusted from the MSDN article you linked):
public class TestDbAsyncEnumerable<T> : EnumerableQuery<T>, IDbAsyncEnumerable<T>, IQueryable<T>
{
public TestDbAsyncEnumerable(IEnumerable<T> enumerable) : base(enumerable)
{ }
public TestDbAsyncEnumerable(Expression expression) : base(expression)
{ }
public IDbAsyncEnumerator<T> GetAsyncEnumerator()
{
return new TestDbAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
}
IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator()
{
return GetAsyncEnumerator();
}
IQueryProvider IQueryable.Provider
{
get { return new TestDbAsyncQueryProvider<T>(this); }
}
}
This is more a solution / work around than an actual question. I'm posting it here since I couldn't find this solution on stack overflow or indeed after a lot of Googling.
The Problem:
I have an MVC 3 webapp using EF 4 code first that I want to write unit tests for. I'm also using NCrunch to run the unit tests on the fly as I code, so I'd like to avoid backing onto an actual database here.
Other Solutions:
IDataContext
I've found this the most accepted way to create an in memory datacontext. It effectively involves writing an interface IMyDataContext for your MyDataContext and then using the interface in all your controllers. An example of doing this is here.
This is the route I went with initially and I even went as far as writing a T4 template to extract IMyDataContext from MyDataContext since I don't like having to maintain duplicate dependent code.
However I quickly discovered that some Linq statements fail in production when using IMyDataContext instead of MyDataContext. Specifically queries like this throw a NotSupportedException
var siteList = from iSite in MyDataContext.Sites
let iMaxPageImpression = (from iPage in MyDataContext.Pages where iSite.SiteId == iPage.SiteId select iPage.AvgMonthlyImpressions).Max()
select new { Site = iSite, MaxImpressions = iMaxPageImpression };
My Solution
This was actually quite simple. I simply created a MyInMemoryDataContext subclass to MyDataContext and overrode all the IDbSet<..> properties as below:
public class InMemoryDataContext : MyDataContext, IObjectContextAdapter
{
/// <summary>Whether SaveChanges() was called on the DataContext</summary>
public bool SaveChangesWasCalled { get; private set; }
public InMemoryDataContext()
{
InitializeDataContextProperties();
SaveChangesWasCalled = false;
}
/// <summary>
/// Initialize all MyDataContext properties with appropriate container types
/// </summary>
private void InitializeDataContextProperties()
{
Type myType = GetType().BaseType; // We have to do this since private Property.Set methods are not accessible through GetType()
// ** Initialize all IDbSet<T> properties with CollectionDbSet<T> instances
var DbSets = myType.GetProperties().Where(x => x.PropertyType.IsGenericType && x.PropertyType.GetGenericTypeDefinition() == typeof(IDbSet<>)).ToList();
foreach (var iDbSetProperty in DbSets)
{
var concreteCollectionType = typeof(CollectionDbSet<>).MakeGenericType(iDbSetProperty.PropertyType.GetGenericArguments());
var collectionInstance = Activator.CreateInstance(concreteCollectionType);
iDbSetProperty.SetValue(this, collectionInstance,null);
}
}
ObjectContext IObjectContextAdapter.ObjectContext
{
get { return null; }
}
public override int SaveChanges()
{
SaveChangesWasCalled = true;
return -1;
}
}
In this case my CollectionDbSet<> is a slightly modified version of FakeDbSet<> here (which simply implements IDbSet with an underlying ObservableCollection and ObservableCollection.AsQueryable()).
This solution works nicely with all my unit tests and specifically with NCrunch running these tests on the fly.
Full Integration Tests
These Unit tests test all the business logic but one major downside is that none of your LINQ statements are guaranteed to work with your actual MyDataContext. This is because testing against an in memory data context means you're replacing the Linq-To-Entity provider but a Linq-To-Objects provider (as pointed out very well in the answer to this SO question).
To fix this I use Ninject within my unit tests and setup InMemoryDataContext to bind instead of MyDataContext within my unit tests. You can then use Ninject to bind to an actual MyDataContext when running the integration tests (via a setting in the app.config).
if(Global.RunIntegrationTest)
DependencyInjector.Bind<MyDataContext>().To<MyDataContext>().InSingletonScope();
else
DependencyInjector.Bind<MyDataContext>().To<InMemoryDataContext>().InSingletonScope();
Let me know if you have any feedback on this however, there are always improvements to be made.
As per my comment in the question, this was more to help others searching for this problem on SO. But as pointed out in the comments underneath the question there are quite a few other design approaches that would fix this problem.