admin管理员组

文章数量:1122832

We are using Nhibernate v4.0.30319 and we are using Flushmode.Commit. Let's consider an example Employee table with IsActive column in DB.

In one of the transaction we are fetching the Employee with empId = 100 as below:

var employee = session.Get<Employee>(100);

employee.IsActive = false;

It is not yet committed and not even flushed.

Immediately we are running the query to fetch all employees who are active.

var activeEmployees = session.CreateCriteria<Employee>()
                             .Add(Restrictions.Eq("IsActive", true))
                             .List<Employee>();

Now in the activeEmployees result I am still getting the Employee details of empId=1 but with IsActive value as false.

I am not able to understand why this inconsistent behaviour. If the query is running on the DB then it should return empId -100 with IsActive value 'True' else if it is running on first level cache it should not include empId-100 in the query result. Here it is returning EmpId-1 with IsActive false.

Why it is behaving like this? I have gone through some articles and configurations details but I am not able to figure out about this behaviour.

I have created a console app:

Employee Table:

Nhibernate configuration:

 if (_sessionFactory == null)
 {
     var configuration = new Configuration();

     // Set connection properties for SQL Server
     configuration.SetProperty(NHibernate.Cfg.Environment.ConnectionDriver, typeof(SqlClientDriver).AssemblyQualifiedName);
     configuration.SetProperty(NHibernate.Cfg.Environment.ConnectionString, "Data Source=INLT-D72FCSG3\\SQLEXPRESS;Initial Catalog=TestDB;Integrated Security=True;");
     configuration.SetProperty(NHibernate.Cfg.Environment.Dialect, typeof(MsSql2012Dialect).AssemblyQualifiedName);
     configuration.SetProperty(NHibernate.Cfg.Environment.ShowSql, "true");
     configuration.SetProperty(NHibernate.Cfg.Environment.FormatSql, "true");
     configuration.SetProperty(NHibernate.Cfg.Environment.Hbm2ddlAuto, "update");


     configuration.AddFile("Employee.hbm.xml"); // Add your mapping files
     _sessionFactory = configuration.BuildSessionFactory();
 }
 return _sessionFactory;

Execute:

 using (var session = NHibernateHelper.OpenSession())
 {
     session.FlushMode = FlushMode.Commit;
     // Start a new transaction
     using (var transaction = session.BeginTransaction())
     {
         // Load employee with Id = 100
         var employee = session.Get<Employee>(1);
         Console.WriteLine($"Before Update: {employee.Name} - IsActive: {employee.IsActive}");
     // Modify the IsActive field to false (this marks the entity as dirty)
     employee.IsActive = false;

     // The entity is now in the session cache with IsActive = false
     Console.WriteLine($"After Update: {employee.Name} - IsActive: {employee.IsActive}");

     // Now, we fetch active employees (IsActive = true)
     var activeEmployees = session.CreateCriteria<Employee>()
                                  .Add(Restrictions.Eq("IsActive", true))
                                  .List<Employee>();

     // Print the active employees (it should still return the modified entity in the session cache)
     Console.WriteLine("\nActive Employees (before commit):");
     foreach (var emp in activeEmployees)
     {
         Console.WriteLine($"{emp.Name} - IsActive: {emp.IsActive}");
     }

     // Commit the transaction to persist changes to the database
     transaction.Commit();
 }

}

  // Simulate a new session for the next query (to see changes after commit)
 using (var session = NHibernateHelper.OpenSession())
 {
     var activeEmployees = session.CreateCriteria<Employee>()
                                  .Add(Restrictions.Eq("IsActive", true))
                                  .List<Employee>();

     // Print the active employees after the session is committed
     Console.WriteLine("\nActive Employees (after commit):");
     foreach (var emp in activeEmployees)
     {
         Console.WriteLine($"{emp.Name} - IsActive: {emp.IsActive}");
     }
 }

OutPut:

NHibernate:
    SELECT
        employee0_.Id as id1_0_0_,
        employee0_.Name as name2_0_0_,
        employee0_.IsActive as isactive3_0_0_
    FROM
        Employee employee0_
    WHERE
        employee0_.Id=@p0;
    @p0 = 1 [Type: Int32 (0:0:0)]
Before Update: John Doe - IsActive: True
After Update: John Doe - IsActive: False
NHibernate:
    SELECT
        this_.Id as id1_0_0_,
        this_.Name as name2_0_0_,
        this_.IsActive as isactive3_0_0_
    FROM
        Employee this_
    WHERE
        this_.IsActive = @p0;
    @p0 = True [Type: Boolean (0:0:0)]

Active Employees (before commit):
John Doe - IsActive: False
Jane Smith - IsActive: True
Bob Brown - IsActive: True
Alice Green - IsActive: True
NHibernate:
    SELECT
        this_.Id as id1_0_0_,
        this_.Name as name2_0_0_,
        this_.IsActive as isactive3_0_0_
    FROM
        Employee this_
    WHERE
        this_.IsActive = @p0;
    @p0 = True [Type: Boolean (0:0:0)]

Active Employees (after commit):
Jane Smith - IsActive: True
Bob Brown - IsActive: True
Alice Green - IsActive: True

Thanks,

Nagasree.

We are using Nhibernate v4.0.30319 and we are using Flushmode.Commit. Let's consider an example Employee table with IsActive column in DB.

In one of the transaction we are fetching the Employee with empId = 100 as below:

var employee = session.Get<Employee>(100);

employee.IsActive = false;

It is not yet committed and not even flushed.

Immediately we are running the query to fetch all employees who are active.

var activeEmployees = session.CreateCriteria<Employee>()
                             .Add(Restrictions.Eq("IsActive", true))
                             .List<Employee>();

Now in the activeEmployees result I am still getting the Employee details of empId=1 but with IsActive value as false.

I am not able to understand why this inconsistent behaviour. If the query is running on the DB then it should return empId -100 with IsActive value 'True' else if it is running on first level cache it should not include empId-100 in the query result. Here it is returning EmpId-1 with IsActive false.

Why it is behaving like this? I have gone through some articles and configurations details but I am not able to figure out about this behaviour.

I have created a console app:

Employee Table:

Nhibernate configuration:

 if (_sessionFactory == null)
 {
     var configuration = new Configuration();

     // Set connection properties for SQL Server
     configuration.SetProperty(NHibernate.Cfg.Environment.ConnectionDriver, typeof(SqlClientDriver).AssemblyQualifiedName);
     configuration.SetProperty(NHibernate.Cfg.Environment.ConnectionString, "Data Source=INLT-D72FCSG3\\SQLEXPRESS;Initial Catalog=TestDB;Integrated Security=True;");
     configuration.SetProperty(NHibernate.Cfg.Environment.Dialect, typeof(MsSql2012Dialect).AssemblyQualifiedName);
     configuration.SetProperty(NHibernate.Cfg.Environment.ShowSql, "true");
     configuration.SetProperty(NHibernate.Cfg.Environment.FormatSql, "true");
     configuration.SetProperty(NHibernate.Cfg.Environment.Hbm2ddlAuto, "update");


     configuration.AddFile("Employee.hbm.xml"); // Add your mapping files
     _sessionFactory = configuration.BuildSessionFactory();
 }
 return _sessionFactory;

Execute:

 using (var session = NHibernateHelper.OpenSession())
 {
     session.FlushMode = FlushMode.Commit;
     // Start a new transaction
     using (var transaction = session.BeginTransaction())
     {
         // Load employee with Id = 100
         var employee = session.Get<Employee>(1);
         Console.WriteLine($"Before Update: {employee.Name} - IsActive: {employee.IsActive}");
     // Modify the IsActive field to false (this marks the entity as dirty)
     employee.IsActive = false;

     // The entity is now in the session cache with IsActive = false
     Console.WriteLine($"After Update: {employee.Name} - IsActive: {employee.IsActive}");

     // Now, we fetch active employees (IsActive = true)
     var activeEmployees = session.CreateCriteria<Employee>()
                                  .Add(Restrictions.Eq("IsActive", true))
                                  .List<Employee>();

     // Print the active employees (it should still return the modified entity in the session cache)
     Console.WriteLine("\nActive Employees (before commit):");
     foreach (var emp in activeEmployees)
     {
         Console.WriteLine($"{emp.Name} - IsActive: {emp.IsActive}");
     }

     // Commit the transaction to persist changes to the database
     transaction.Commit();
 }

}

  // Simulate a new session for the next query (to see changes after commit)
 using (var session = NHibernateHelper.OpenSession())
 {
     var activeEmployees = session.CreateCriteria<Employee>()
                                  .Add(Restrictions.Eq("IsActive", true))
                                  .List<Employee>();

     // Print the active employees after the session is committed
     Console.WriteLine("\nActive Employees (after commit):");
     foreach (var emp in activeEmployees)
     {
         Console.WriteLine($"{emp.Name} - IsActive: {emp.IsActive}");
     }
 }

OutPut:

NHibernate:
    SELECT
        employee0_.Id as id1_0_0_,
        employee0_.Name as name2_0_0_,
        employee0_.IsActive as isactive3_0_0_
    FROM
        Employee employee0_
    WHERE
        employee0_.Id=@p0;
    @p0 = 1 [Type: Int32 (0:0:0)]
Before Update: John Doe - IsActive: True
After Update: John Doe - IsActive: False
NHibernate:
    SELECT
        this_.Id as id1_0_0_,
        this_.Name as name2_0_0_,
        this_.IsActive as isactive3_0_0_
    FROM
        Employee this_
    WHERE
        this_.IsActive = @p0;
    @p0 = True [Type: Boolean (0:0:0)]

Active Employees (before commit):
John Doe - IsActive: False
Jane Smith - IsActive: True
Bob Brown - IsActive: True
Alice Green - IsActive: True
NHibernate:
    SELECT
        this_.Id as id1_0_0_,
        this_.Name as name2_0_0_,
        this_.IsActive as isactive3_0_0_
    FROM
        Employee this_
    WHERE
        this_.IsActive = @p0;
    @p0 = True [Type: Boolean (0:0:0)]

Active Employees (after commit):
Jane Smith - IsActive: True
Bob Brown - IsActive: True
Alice Green - IsActive: True

Thanks,

Nagasree.

Share Improve this question edited yesterday NAGASREE asked yesterday NAGASREE NAGASREE 3744 silver badges16 bronze badges 0
Add a comment  | 

1 Answer 1

Reset to default 1

When first you get the employee with ID 100, the entity get cached in first level cache. Then you set it's IsActive to false. Hence, the entity in first level cache is updated; not reflected to the database yet. Value in the database is still true.

Then you query for all the employees where IsActive is true. The query must be building something like below:

SELECT * FROM Employee WHERE IsActive = true

As said above, the IsActive value for employee id 100 is still true in the database, so employee 100 is also returned as a part of result set.

THEN NHibernate builds Entity objects for all the rows returned. Other rows are not in the first level cache yet, so it builds them as new one. But, NHibernate finds that Entity object for employee 100 already exists in the first level cache, so it does not build it, it simply use it from the first level cache. As the IsActive is false in first level cache, you see the mismatch.

This is correct and expected behaviour; this is how NHibernate works.

本文标签: cNhibernate Why session cache and query results mismatchStack Overflow