Is there a way to set optimistic concurrency to true in Raven.Server.exe.config? Or, can it somehow be applied at the database level? On RavenDB's site, I see a couple of mentions of setting UseOptimisticConcurrency = true, but it looks like it's at the session level within the code:
public void Save<T>(T objectToSave)
{
using (IDocumentSession session = Database.OpenSession())
{
session.Advanced.UseOptimisticConcurrency = true; // This is the setting
Guid eTag = (Guid)session.Advanced.GetEtagFor(objectToSave);
session.Store(objectToSave, eTag);
session.SaveChanges();
}
}
I would like to know if it that setting exists somewhere server-wide, so it doesn't need to be specified for each session in code.
Edit: The code above produces the following error. Trying to find out why...
Edit 2: Ok, I'm making progress. If I retrieve the object, and call GetEtagFor() all within the same session, then I get a valid eTag. So I guess my main question now is: Is the correct way to use a session, within a client UI, to open the session once when the app starts, and then close it at the end? And... What's the correct way to store the eTag? The way it's coded above, the eTag is retrieved right before storing, which I would imagine is the wrong way to do it. I'm guessing the eTag should be retrieved when the object is first retrieved. But when we originally get a list of objects, should we have to loop through each and call GetEtagFor() on them? Doesn't seem right...
Bob,
No, UseOptimisticConcurrency is something that you need to setup when you open the session.
And NO, a single session per the entire application is the wrong thing to do. See this article for more details on session management:
http://archive.msdn.microsoft.com/mag200912NHibernate
It talks about NHibernate, but the session management parts applies to ravendb as well.
Disclaimer: This is not a recommended approach, and in fact bad practice to open an IDocumentSession that will live as long as the client app lives. For an alternate solution, see the answer posted here: RavenDB Catch 22 - Optimistic Concurrency AND Seeing Changes from Other Clients.
It looks like I got optimistic concurrency working, so I thought I'd post this to help any else.
First, in DataAccessLayerBase, I initialize the DocumentStore and IDocumentSession. These will be open and used as long as the client app is running.
public abstract class DataAccessLayerBase
{
protected static DocumentStore Database { get; private set; }
protected static IDocumentSession Session { get; private set; }
static DataAccessLayerBase()
{
if (Database != null) { return; }
Database = GetDatabase();
Session = GetSession();
}
private static DocumentStore GetDatabase()
{
string databaseUrl = ConfigurationManager.AppSettings["databaseUrl"];
DocumentStore documentStore = new DocumentStore();
try
{
documentStore.Url = databaseUrl;
documentStore.Initialize();
}
catch
{
documentStore.Dispose();
throw;
}
return documentStore;
}
private static IDocumentSession GetSession()
{
IDocumentSession session = Database.OpenSession();
session.Advanced.UseOptimisticConcurrency = true;
return session;
}
}
Next, when retrieving the data, use the existing session:
public class CustomVariableGroupData : DataAccessLayerBase, ICustomVariableGroupData
{
public IEnumerable<CustomVariableGroup> GetAll()
{
return Session.Query<CustomVariableGroup>();
}
}
Finally, when saving, get the eTag and save.
public class GenericData : DataAccessLayerBase, IGenericData
{
public void Save<T>(T objectToSave)
{
Guid eTag = (Guid)Session.Advanced.GetEtagFor(objectToSave);
Session.Store(objectToSave, eTag);
Session.SaveChanges();
}
}
If another instance of the UI is running, and changes the object, a concurrency exception will occur. And that's what we wanted.
I just looked at the title of this post again, and realized this doesn't answer the question of how to set concurrency in the server config file. However, since it can now be set once in the data layer, that's good enough for me.
Related
I'm using the CQRS pattern to get the data from the DB using NHibernate.
Here is the CommittingTransactionCommandHandler which calls the UpdateProductHandler
class CommittingTransactionCommandHandler
{
private readonly ISession session;
private readonly ICommandHandler<TCommand> _inner; //Generic Command Handlers
public CommittingTransactionCommandHandler(ISession session)
{
this.session = session;
}
public async Task Execute(TCommand command)
{
using (var txn = session.BeginTransaction(IsolationLevel.Unspecified))
{
try
{
await _inner.Update(command); // This calls the UpdateProducthandler's Update method
txn.Commit();
}
catch (Exception ex)
{
throw;
}
}
}
}
Here is the Command Handler for the Update.
class UpdateProductHandler : ICommand
{
private readonly ISession session;
public UpdateProductHandler(ISession session)
{
this.session = session;
}
public async Task Update(int id, ProductIdentity productIdentity)
{
var product = session.Get(id);
product.Update(productIdentity);
}
}
Here is the Query Handler for the Get
class GetProductHandler
{
private readonly ISession session;
public GetProductHandler(ISession session)
{
this.session = session;
}
public async Task<Product> Get(int id)
{
var product = session.Get(id);
if (product == null)
throw new Exception("Entity not found");
return Task.FromResult(product);
}
}
Here is the code for the Product entity
class Product
{
public virtual int Id { get; protected set; }
public virtual string Name { get; protected set; }
public virtual string Description { get; protected set; }
public virtual int? Version { get; protected set; }
public virtual void Update(ProductIdentity productIdentity)
{
Name = productIdentity.Name;
Description = productIdentity.Description;
}
}
The flow is
CommittingTransactionCommandHandler is a generic command handler. This is called from the API, which internally invokes the UpdateProductHandler. The transaction is opened in this and committed here.
The scenario is that
I get a Product from the DB using the GetProductHandler. (In this case, the version number of the Product is 10.)
I'm updating the Product using the UpdateProductHandler and commits the session which is under the transaction. (Here version number of the Product is 11)
Immediately after the Update Product, I query the same Product using the GetProductHandler and loads it in the Edit mode in the UI. (But the Product fetched using the GetProductHandler has a version number 10 and not 11.)
Here is the issue, instead of getting the latest update from the DB, the above GetProductHandler, gets the previous state of the object.(Found using the version number)
Now, if I try to update the Product, I get a Stale Object State Exception since the version number is 10 which is not the latest version of the Product.
I've tried with session.Refresh(product) but all in vain as it affects the other transactions.
How can I resolve this?
As Ayende explains, Get will NOT always hit the database. It will only hit the database if entity not found in first level cache.
You have not explained how you are updating the entity; what is inside product.Update method. If you are updating using API that does not update underlying first level cache (SQL/HQL/Linq), then the problem you stated in question is obvious. In that case,
You load entity in session cache using Get (Version 10). This hits the database.
Then, you call Update (database hit) which will not update the first level cache (Version changed to 11 in database; NOT in cache).
Then you call Get again. NHibernate looks if entity is already loaded in session cache. Yes; it is (Version 10). It just returns it. No database hit.
Solution 1:
Not sure why that Update method is needed. You can directly update the entity like below:
public async Task Update(int id, ProductIdentity productIdentity)
{
var product = session.Get(id);
product.Version = 11;
//Update other properties here
...
...
//That's it. You are already calling `Flush` somewhere somehow
}
Solution 2:
As Ayende NOT recommended (and I am not recommending either), don't use Get and write a query that will hit the database. Use Linq/HQL/SQL API instead.
select customer from s.Linq<Customer>()
where customer.Id = customerId
select customer
).FirstOrDefault();
Every time that I see something like that, I wince a little inside. The reason for that is quite simple. This is doing a query by primary key. The key word here is a query.
This means that we have to hit the database in order to get a result for this query. Unless you are using the query cache (which by default you won’t), this force a query on the database, bypassing both the first level identity map and the second level cache.
Get and Load are here for a reason, they provide a way to get an entity by primary key. That is important for several aspects, most importantly, it means that NHibernate can apply quite a few optimizations for this process.
I have an MVC4 site that needs to maintain some information while (and ONLY while) the user is logged in. For example, once the user logs in, I get a 'user token' back that allows me access to several off site services.
I've tried two different approaches. The first was to use a public static class that accesses the user session. However, after reading up on static classes, I'm hesitant to use them. According to what I'm reading, static classes should only be used for read only objects, and I wasn't using it that way. Although the site site did seem to be working fine with a limited number of users (currently there's 10).
(If someone would like to explain to me why this is a bad idea in MVC4, please tell me and/or link to an article)
public class SessionAccessorClasses
{
public const string SessionAccessorSessionVariablesString = "_SessionAccessorSessionVariables";
public static SessionAccessorModel SessionVariables
{
get { return System.Web.HttpContext.Current.Session != null ? (SessionAccessorModel)System.Web.HttpContext.Current.Session[SessionAccessorSessionVariablesString] : null; }
set { System.Web.HttpContext.Current.Session.Add(SessionAccessorSessionVariablesString, value); }
}
}
My second (and current) approach is to use Session variables and access them using a globally available class.
public class SessionAccessorClasses
{
private const string SessionAccessorSessionVariablesString = "_SessionAccessorSessionVariables";
public SessionAccessorModel GetSessionVariables()
{
return System.Web.HttpContext.Current.Session != null ? (SessionAccessorModel)System.Web.HttpContext.Current.Session[SessionAccessorSessionVariablesString] : null;
}
public void SetSessionVariables(SessionAccessorModel value)
{
System.Web.HttpContext.Current.Session.Add(SessionAccessorSessionVariablesString, value);
}
public void ClearSessionVariables()
{
System.Web.HttpContext.Current.Session.Remove(SessionAccessorSessionVariablesString);
}
}
This works fine, but I hesitate to call it good is because I don't fully understand why the public static class was such a bad idea, and because I now have to instantiate my new class at the beginning of nearly every function, and call the Set/Update function at the end of every function; which feels wrong somehow.
So first, since my original static class was accessing the users session, is it really that bad?
Second, is my second class a more appropriate way of doing things? Can you suggest improvements?
Third, if nothing else, can you give me the positive/negative aspects of doing it either way?
You want to use Session in ASP.net. It was created for the purpose you describe.
ASP.NET session state enables you to store and retrieve values for a user as the user navigates ASP.NET pages in a Web application. HTTP is a stateless protocol. This means that a Web server treats each HTTP request for a page as an independent request. The server retains no knowledge of variable values that were used during previous requests. ASP.NET session state identifies requests from the same browser during a limited time window as a session, and provides a way to persist variable values for the duration of that session. By default, ASP.NET session state is enabled for all ASP.NET applications.
I'm a fan of strongly-typed reusable session variables, so I wrote the following extensions to store whatever variables you want to create without the need to constantly remember magic strings.
public static class SessionExtensions
{
public static bool TryGetValue<T>(this HttpSessionStateBase session, out T value)
where T : class
{
var name = typeof(T).FullName;
value = session[name] as T;
var result = value != null;
return result;
}
public static void SetValue<T>(this HttpSessionStateBase session, T value)
{
var name = typeof(T).FullName;
session[name] = value;
}
public static void RemoveValue<T>(this HttpSessionStateBase session)
{
var name = typeof(T).FullName;
session[name] = null;
}
public static bool ValueExists(this HttpSessionStateBase session, Type objectType)
{
var name = objectType.FullName;
var result = session[name] != null;
return result;
}
}
So if you have a class:
public MyClass
{
public int MyInt { get; set; }
}
You can store it by simply:
Session.SetValue(MyClass);
that needs to maintain some information while (and ONLY while) the user is logged in.
These methods could be updated a few ways to fulfill this requirement. Here is one way:
public static bool TryGetAuthenticatedValue<T>(this HttpSessionStateBase session,
out T value)
where T : class
{
value = null;
if (HttpContext.Current.User != null
&& HttpContext.Current.User.Identity != null
&& HttpContext.Current.User.IsAuthenticated)
{
var name = typeof(T).FullName;
value = session[name] as T;
}
var result = value != null;
return result;
}
I would also recommend that whatever classes you store in session, be serializable. That is to say it has a parameterless constructor and marked as [Serializable].
While my service executes, many classes will need to access User.Current (that is my own User class). Can I safely store _currentUser in a [ThreadStatic] variable? Does WCF reuse its threads? If that is the case, when will it clean-up the ThreadStatic data? If using ThreadStatic is not safe, where should I put that data? Is there a place inside OperationContext.Current where I can store that kind of data?
Edit 12/14/2009: I can assert that using a ThreadStatic variable is not safe. WCF threads are in a thread pool and the ThreadStatic variable are never reinitialized.
There's a blog post which suggests implementing an IExtension<T>. You may also take a look at this discussion.
Here's a suggested implementation:
public class WcfOperationContext : IExtension<OperationContext>
{
private readonly IDictionary<string, object> items;
private WcfOperationContext()
{
items = new Dictionary<string, object>();
}
public IDictionary<string, object> Items
{
get { return items; }
}
public static WcfOperationContext Current
{
get
{
WcfOperationContext context = OperationContext.Current.Extensions.Find<WcfOperationContext>();
if (context == null)
{
context = new WcfOperationContext();
OperationContext.Current.Extensions.Add(context);
}
return context;
}
}
public void Attach(OperationContext owner) { }
public void Detach(OperationContext owner) { }
}
Which you could use like that:
WcfOperationContext.Current.Items["user"] = _currentUser;
var user = WcfOperationContext.Current.Items["user"] as MyUser;
An alternative solution without adding extra drived class.
OperationContext operationContext = OperationContext.Current;
operationContext.IncomingMessageProperties.Add("SessionKey", "ABCDEFG");
To get the value
var ccc = aaa.IncomingMessageProperties["SessionKey"];
That's it
I found that we miss the data or current context when we make async call with multiple thread switching. To handle such scenario you can try to use CallContext. It's supposed to be used in .NET remoting but it should also work in such scenario.
Set the data in the CallContext:
DataObject data = new DataObject() { RequestId = "1234" };
CallContext.SetData("DataSet", data);
Retrieving shared data from the CallContext:
var data = CallContext.GetData("DataSet") as DataObject;
// Shared data object has to implement ILogicalThreadAffinative
public class DataObject : ILogicalThreadAffinative
{
public string Message { get; set; }
public string Status { get; set; }
}
Why ILogicalThreadAffinative ?
When a remote method call is made to an object in another AppDomain,the current CallContext class generates a LogicalCallContext that travels along with the call to the remote location.
Only objects that expose the ILogicalThreadAffinative interface and are stored in the CallContext are propagated outside the AppDomain.
I'm running into issues with my ISessions in NHibernate. I keep getting "Session Closed!" errors. Can some one please show me the correct pattern including a definition of the following methods and when to use each:
ISession.Close()
ISession.Dispose()
ISession.Disconnect()
Here's my problem. I have a callback setup to fire off a process that awards badges to players every couple of minutes. However I keep getting "Session Closed!" errors or errors about not being able to associate collections.
Here's my Repository:
public class NHibernateRepository : IRepository
{
#region Fields
private ISession _session;
private readonly ISessionFactory _sessionFactory;
#endregion
#region Constructors
public NHibernateRepository(ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
}
#endregion
#region IRepository Implementation
public ISession OpenSession()
{
_session = _sessionFactory.OpenSession();
return _session;
}
public IQueryable<TModel> All<TModel>()
{
return _session.Linq<TModel>();
}
public void Save<TModel>(TModel model)
{
_session.Save(model);
}
public void Update<TModel>(TModel model)
{
_session.Update(model);
}
public void Delete<TModel>(TModel model)
{
_session.Delete(model);
}
public ITransaction BeginTransaction()
{
return _session.BeginTransaction();
}
public void Flush()
{
_session.Flush();
}
#endregion
}
Here's my usage. The repository is getting injected via Structure Map
private Object _awardBadgesLock = new object(); //In case the callback happens again before the previous one completes
public void AwardBadges()
{
lock (_awardBadgesLock)
{
using(session = _repository.OpenSession())
{
foreach (var user in _repository.All<User>().ToList())
{
var userPuzzles = _repository.All<Puzzle>().ByUser(user.Id).ToList();
var userVotes = _repository.All<Vote>().Where(x => x.UserId == user.Id).ToList();
var userSolutions = _repository.All<Solution>().ByUser(user.Id).ToList().Where(x => !userPuzzles.Select(y => y.Id).Contains(x.PuzzleId));
var ledPuzzles = GetPuzzlesLedByUser(user.Id);
AwardPlayerBadge(user, userSolutions);
AwardCriticBadge(user, userVotes);
AwardCreatorBadge(user, userPuzzles);
AwardRidlerBadge(user, userPuzzles);
AwardSupporterBadge(user, userVotes);
AwardPopularBadge(user, userPuzzles);
AwardNotableBadge(user, userPuzzles);
AwardFamousBadge(user, userPuzzles);
AwardLeaderBadge(user, ledPuzzles);
using (var tx = _repository.BeginTransaction())
{
_repository.Update(user);
tx.Commit();
}
}
}
}
}
You should always use session.Dispose();
The other are for very strange occurances
I advice you to read the documentation of ISession on
https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk/nhibernate/src/NHibernate/ISession.cs
Anyway the proper way to clean up when you are finished with the session is to dispose it (or better, surround the usage with using statement). In this case, "using" closes the session and suppresses the finalizer, i.e. it prevents the session object from unnecessarily surviving the next garbage collecting and saves the memory.
If the connection is already closed, disposing it will not throw an exception. On the other hand, closing after disposing (or after closing) throws an exception.
The documentation recommends calling disconnect instead of closing, because this releases the connection to the connection pool. You should call Reconnect before using a disconnected session.
For my needs, I always use "using" which calls Dispose and have never used the othe two functions.
The issue lies in the fact the ISession is not thread-safe. There were multiple methods being fired on separate threads that all created an instance of ISession. The issue was really with the fact that they all shared the same SessionFactory. Image both of these methods are fired off on separate threads:
ISessionFactory _sessionFactory;
void MethodOne()
{
using(ISession session = _sessionFactory.OpenSession())
{
//Do something with really quick with the session
//Then dispose of it
}
}
void MethodTwo()
{
//OpenSession() actually returns the same instance used in the
//previous method that has already disposed of the object;
using(ISession session = _sessionFactory.OpenSession())
{
//Do something with a session that has already been disposed
//throws errors
}
}
How I fixed it was basically ditching NHIbernate in these scenarios and called stored procs instead. I think it turned out to be more performant in my situation anyway.
About the problem, your method of locking is right as long as you dispose the session but probably the bug lies under another part of your codes. by the way about the design, it is better that you pass the session variable to repositories because of unit of work implementation of the session and aggregate root's transaction like this:
using (ISession session = SessionFactory.OpenSession())
{
Repository1 rep1 = new Repository1(session);
Repository2 rep1 = new Repository2(session);
Repository3 rep1 = new Repository3(session);
// some logics
using (var tx = session.BeginTransaction())
tx.Commit();
}
.
.
.
I'm using Castle ActiveRecord for persistence, and I'm trying to write a base class for my persistence tests which will do the following:
Open a transaction for each test case and roll it back at the end of the test case, so that I get a clean DB for each test case without me having to rebuild the schema for each test case.
Provide the ability to flush my NHibernate session and get a new one in the middle of a test, so that I know that my persistence operations have really hit the DB rather than just the NHibernate session.
In order to prove that my base class (ARTestBase) is working, I've come up with the following sample tests.
[TestFixture]
public class ARTestBaseTest : ARTestBase
{
[Test]
public void object_created_in_this_test_should_not_get_committed_to_db()
{
ActiveRecordMediator<Entity>.Save(new Entity {Name = "test"});
Assert.That(ActiveRecordMediator<Entity>.Count(), Is.EqualTo(1));
}
[Test]
public void object_created_in_previous_test_should_not_have_been_committed_to_db()
{
ActiveRecordMediator<Entity>.Save(new Entity {Name = "test"});
Assert.That(ActiveRecordMediator<Entity>.Count(), Is.EqualTo(1));
}
[Test]
public void calling_flush_should_make_nhibernate_retrieve_fresh_objects()
{
var savedEntity = new Entity {Name = "test"};
ActiveRecordMediator<Entity>.Save(savedEntity);
Flush();
// Could use FindOne, but then this test would fail if the transactions aren't being rolled back
foreach (var entity in ActiveRecordMediator<Entity>.FindAll())
{
Assert.That(entity, Is.Not.SameAs(savedEntity));
}
}
}
Here is my best effort at the base class. It correctly implements Flush(), so the third test case passes. However it does not rollback the transactions, so the second test fails.
public class ARTestBase
{
private SessionScope sessionScope;
private TransactionScope transactionScope;
[TestFixtureSetUp]
public void InitialiseAR()
{
ActiveRecordStarter.ResetInitializationFlag();
ActiveRecordStarter.Initialize(typeof (Entity).Assembly, ActiveRecordSectionHandler.Instance);
ActiveRecordStarter.CreateSchema();
}
[SetUp]
public virtual void SetUp()
{
transactionScope = new TransactionScope(OnDispose.Rollback);
sessionScope = new SessionScope();
}
[TearDown]
public virtual void TearDown()
{
sessionScope.Dispose();
transactionScope.Dispose();
}
protected void Flush()
{
sessionScope.Dispose();
sessionScope = new SessionScope();
}
[TestFixtureTearDown]
public virtual void TestFixtureTearDown()
{
SQLiteProvider.ExplicitlyDestroyConnection();
}
}
Note that I'm using a custom SQLite provider with an in-memory database. My custom provider, taken from this blog post, keeps the connection open at all times to maintain the schema. Removing this and using a regular SQL Server database doesn't change the behaviour.
Is there a way to acheive the required behaviour?
Not too sure about ActiveRecord, but in NHibernate a transaction belongs to a session, not the otherway round.
If you've used ADO.Net a lot, this will make more sense, as to create an IDbTransaction you need to use the connection. ActiveRecord's TransactionScope (and NHibnerate's ITransaction) essentially wrap an IDbTransaction, so you need to create the SessionScope before the TransactionScope.
What you might also find (depending on if you're using NHibernate 1.2 GA or NHibernate 2.*, and what FlushMode your SessionScope has) is that your call to FindAll() may cause the session to flush anyway, as NHibernate will realise that it can't retrieve the correct data without actioning the last call to Save.
This all said and done, have you tried using SessionScope.Flush() instead of creating a new SessionScope?
Using SessionScope.Flush() makes my third test fail. As I understand it, Flush() executes the SQL to push my records into the DB, but does not evict objects from the session. That fits with what you say about FindAll() causing a flush.
What I really want is SessionScope.Flush() (to synchronise state of DB with session) plus SessionScope.EvictAll() (to ensure I get fresh objects in subsequent queries). My new SessionScope() was an attempt to simulate EvictAll().
Your comments about the session enclosing the transaction rather than the other way round did give me an idea. I'm not sure how kosher it is to create a new SessionScope inside a TransactionScope inside a flushed SessionScope, and expect it to participate in the transaction, but it seems to work:
public abstract class ARTestBase
{
private SessionScope sessionScope;
private TransactionScope transactionScope;
private bool reverse;
private IList<SessionScope> undisposedScopes;
[TestFixtureSetUp]
public void InitialiseAR()
{
ActiveRecordStarter.ResetInitializationFlag();
ActiveRecordStarter.Initialize(typeof (Entity).Assembly, ActiveRecordSectionHandler.Instance);
ActiveRecordStarter.CreateSchema();
InitialiseIoC();
undisposedScopes = new List<SessionScope>();
}
[SetUp]
public virtual void SetUp()
{
sessionScope = new SessionScope();
transactionScope = new TransactionScope(OnDispose.Rollback);
transactionScope.VoteRollBack();
base.CreateInstanceUnderTest();
reverse = false;
}
[TearDown]
public virtual void TearDown()
{
if (reverse)
{
sessionScope.Dispose();
transactionScope.Dispose();
}
else
{
transactionScope.Dispose();
sessionScope.Dispose();
}
}
[TestFixtureTearDown]
public virtual void TestFixtureTearDown()
{
foreach (var scope in undisposedScopes)
{
scope.Dispose();
}
SQLiteProvider.ExplicitlyDestroyConnection();
}
protected void Flush()
{
reverse = true;
sessionScope.Flush();
undisposedScopes.Add(sessionScope);
sessionScope = new SessionScope();
}
}
On further thought, this won't allow you to flush more than once in each test case. I think I can handle that by tracking the scopes more carefully. I might look into it later.