Kotlin JPA Update not working. Why doesn't JPA do dirty check? - jpa

#Transactional
fun test(){
val people = peopleRepository.findById(id)? peopleRepository.save(peopleEntity)
people.address = "NY"
}
After executing peopleRepository.findById(id), update works fine.
However, after executing save(), update does not work.
Is save() necessary again?
I thought .. if finish this test function and jpa do dirty check on the value changed through people.address.
Because I already did save() above.

I assume you are looking at the generated SQL statements. But without flushing, there are none.
this test works as expected. First does an insert and then an update.
#Test
void test() {
Person person = new Person();
person.setName("Peter");
person = personRepository.save(person);
person.setName("Max");
personRepository.flush();
}

Related

Unit Test with transaction: CREATE DATABASE statement not allowed within multi-statement transaction

I have base class for my unit tests:
public abstract class DatabaseTestsBase
{
protected OvuContext DbContext;
protected TransactionScope TransactionScope;
[SetUp]
public void TestSetup()
{
TransactionScope = new TransactionScope(TransactionScopeOption.RequiresNew);
DbContext = new OvuContext("IntegrationTestContext");
}
[TearDown]
public void TestCleanup()
{
TransactionScope.Dispose();
}
}
And the test itself:
[TestFixture]
public class MyEntityTests : DatabaseTestsBase
{
[Test]
public void MyEntity_Create_HasSucceeded()
{
var myEntity = new MyEntity(Guid.NewGuid());
myEntity.Description = "bla bla bla";
var id = myEntity.Id;
DbContext.MyEntities.Add(myEntity);
DbContext.SaveChanges();
var temp = DbContext.MyEntities.Single(x => x.Id == id);
ComparisonResult result = CompareLogic.Compare(myEntity, temp);
Assert.True(result.AreEqual);
}
}
I got the following error when the test runs:
CREATE DATABASE statement not allowed within multi-statement transaction
The 'strange' thing is that when I run the test a second time, it passes.
I believe you are taking the pattern of rolling back database side-effecting Integration / Unit Tests done under an uncommitted transaction (such as TransactionScope) a bit far :)
Code First EF is attempting to create the database under the context of the ambient TransactionScope, which isn't possible.
In Sql Server (and possibly other RDBMS's), it isn't possible to execute certain statements, such as CREATE DATABASE, command under a transaction. You'll get the same error if you execute the following directly in SSMS:
use master;
BEGIN TRAN
CREATE DATABASE FOO;
-- CREATE DATABASE statement not allowed within multi-statement transaction.
I would suggest that you change your strategy such that you pre-create a permanent, empty test database for testing. Other DDL statements executed by EF Code First, such as CREATE TABLE can be rolled back by the uncommitted TransactionScope.

Using EF with stored procedure and getting error as New transaction is not allowed because there are other threads running in the session

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

Create database with data

I'm trying to create my database (code first) and I want to add some data in it when it's created.
public class InitializerWithData : CreateDatabaseIfNotExists<DatabaseContext>
{
protected override void Seed(DatabaseContext ctx)
{
GroupType gt = new GroupType() { Name = "RNC" };
//save
ctx.GroupType.Add(gt);
ctx.SaveChanges();
}
}
public DatabaseContext()
{
Database.SetInitializer<DatabaseContext>(new InitializerWithData());
Database.CreateIfNotExists();
}
As you can see I wrote my custom initializer but the code inside it is never fired though the database does get created.
So how do I solve this?
When you call Database.CreateIfNotExists(), it doesn't trigger the InitializeDatabase of the initializer. Basically it has separated implementation than the initializer.
If you want the Seed method to be fired. You need to execute a code that causes EF to send a query to the database.
First remove this line.
Database.CreateIfNotExists();
Then just execute a query, the least you could have is something like.
using(var db = new DatabaseContext())
{
db.Set<GroupType>().Any();
}
This code will create the database if it doesn't exist and execute the Seed method.

Entity Framework Db.SaveChanges() not working?

Can u tell me what is the problem?
If you are using two different instances of the DbContext (the db variable as you named it) then nothing will be saved when you call SaveChanges on a context different than the one where your entities are tracked. You need to use the Attach method first.
db.customer_images.Attach(item);
db.SaveChanges();
However I think in your case you can avoid the attach step if you refactor a bit you code and don't use the DbContext from the entity itself.
Before going through my answer, you must check, if you are attaching the item as shown in excepted answer or check this code:.
if (dbStudentDetails != null && dbStudentDetails.Id != 0)
{
// update scenario
item.Id = dbStudentDetails.Id;
_context.Entry(dbStudentDetails).CurrentValues.SetValues(item);
_context.Entry(dbStudentDetails).State = EntityState.Modified;
}
else
{
// create scenario
_context.StudentDetails.Add(item);
}
await _context.SaveChangesAsync();
If above solution doesn't work, then check the below answer.
Saw a very wired issue, and thought to must answer this. as this can
be a major issue if you have lots of constraints and indexes in your
SQL.
db.SaveChanges() wasn't throwing any error, but not working (I have tried Exception or SqlException). This was not working because the Unique constraint was not defined properly while creating the Entity Models.
How you can Identified the issue:
I connected my SQL Server and opened the SQL Profiler.
Just before the db.SaveChanges(), I cleared all my profiler logs and ran the db.SaveChanges(). It logged the statement. I copied the script from the profiler and ran the script in SQL Server.
And bingo, I can see the actual error, which is being thrown at SQL Server side.
(images: have some hints, how you can get the execute statement from Profiler and run on sql server)
What you can do For Entity Framework Core:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Students>().HasIndex(p => new { p.RollNumber, p.PhoneNumber }).IsUnique(true).IsClustered(false).HasDatabaseName("IX_Students_Numbers");
}
What you can do For Entity Framework 6 and below:
using System.Data.Entity.ModelConfiguration;
internal partial class StudentsConfiguration : EntityTypeConfiguration<Students>
{
public StudentsConfiguration()
{
HasIndex(p => new { p.RollNumber, p.PhoneNumber }).IsUnique(true).IsClustered(false).HasName("IX_Students_Numbers");
}
}
Try to query your entity by Id, eg:
entity = this.repo.GetById(item.id);
entity.is_front = false;
if (dbSaveChanges() > 0)
{
....
}

Is this safe? - NUnit base class opens and rollsback a TransactionScope

I was thinking it would be nice to create a base class for NUnit test fixtures that opens a TransactionScope during the SetUp phase, then rolls back the transaction during tear down.
Something like this:
public abstract class TestFixtureBase
{
private TransactionScope _transaction;
[TestFixtureSetUp]
public void TestFixtureSetup()
{
_transaction = new TransactionScope();
}
[TestFixtureTearDown]
public void TestFixtureTearDown()
{
if (_transaction != null)
{
_transaction.Dispose();
}
}
}
Do you think this is a good idea?
Obviously the database is just a test database, not a live database, but it would still be annoying if it filled up with junk data from the unit tests.
What do other people do when running unit tests that involve a lot of data access?
You want to be careful here. TransactionScope is going to promote the transaction to a distributed transaction if you open up more than one connection to the database. I find that it is easier just to write some simple SQL that clears out the tables of interest to my test class before I start running the test.
EDIT: Normally I would call any test that touches the database an integration test since it involves another system. Typically, I will mock out the database when unit testing my code.
[TestSetup]
public void Setup()
{
foreach (string table in new string[] { "table1", "table2" })
{
ClearTable( table );
}
}
private void ClearTable( string table )
{
...standard stuff to set up connection...
SqlCommand command = connection.CreateCommand() );
command.CommandText = "delete from " + table;
command.ExecuteNonQuery();
... stuff to clean up connection...
}
I've used XtUnit
It automatically rolls back at the end of a unit test. You can simply add a [Rollback] attribute to the test. It's an extension to NUnit or MbUnit