THe call is an API function and I have a snippet of the unit test to test it which fails because of the iObjectScope error.
Unit Test code (I dont know how to do the Format code block)
------------------
IListQualifiersRequest actual;
// lets get an object
actual = target.GetQualifiersRequest(requestID, idleTimeLimit, hostSourceID, startingQualifier, securityToken);
// all fields in object look good prior to call - see below
target.CacheMFQualifiers(actual);
//after call some field are exceptioned as iObjectScope is already closed
Assert.AreEqual(requestID, actual.RequestID);
//TODO determine why the following generate Telerik.OpenAccess.Exceptions.InvalidOperationException: The 'IObjectScope' is already closed
Assert.AreEqual(hostSourceID, actual.HostSourceID);
-----------------------------------
public void CacheMFQualifiers(IListQualifiersRequest request)
{
var sql = "SELECT * FROM ListQualifiersRequestExtent " + "WHERE _requestID == $1";
using (IObjectScope scope = XBDLPObjectScopeProvider.GetNewObjectScope())
{
var result = scope.GetOqlQuery(sql).Execute(request.RequestID);
if (result.Count == 0)
{
scope.Transaction.Begin();
scope.Add(request);
scope.Transaction.Commit();
}
}
}
13 Answers, 1 is accepted
One thing I could think of would be that OA lazy loads a field, and because the scope you used to load the instance is disposed (by leaving the using block) you get an exception when OA tries to do so.
However, I cannot be sure that this is actually the reason. Maybe you can post your interface IListQualifiersRequest?
Regards
Henrik
namespace
XBDLP.Interface
{
public interface IListQualifiersRequest:IDLPRequest
{
Guid HostSourceID { get;}
string StartingQualifier { get;}
IListQualifiersStatus Status { get; }
}
}
[Telerik.OpenAccess.Persistent()]
public class ListQualifiersRequest:DLPRequestBase,IListQualifiersRequest
{
private Guid _hostSourceID;
private string _startingQualifier;
private ListQualifiersStatus _status;
private ListQualifiersRequest()
{
}
public ListQualifiersRequest(Guid requestID, int? idleTimeLimit, Guid hostSourceID, string startingQualifier, DSSecurityToken token)
: base(requestID, token)
{
_hostSourceID = hostSourceID;
_startingQualifier = startingQualifier;
_status = new ListQualifiersStatus(requestID, idleTimeLimit);
}
public Guid HostSourceID
{
get { return _hostSourceID; }
}
public string StartingQualifier
{
get { return _startingQualifier; }
}
public IListQualifiersStatus Status
{
get { return _status; }
}
}
Base class and intrerface
namespace
XBDLP.Interface
{
public interface IDLPRequest
{
Guid RequestID { get; }
string RequestedBy { get; }
DateTime WhenRequested { get; }
}
}
[Telerik.OpenAccess.Persistent(IdentityField = "_requestID")]
public class DLPRequestBase: IDLPRequest
{
private Guid _requestID;
private string _requestedBy;
private DateTime _whenRequested;
internal DLPRequestBase()
{
}
public DLPRequestBase(Guid? requestID, DSSecurityToken token)
{
if (requestID == null)
{
_requestID = Guid.NewGuid();
}
else
{
_requestID = requestID.Value;
}
_whenRequested = DateTime.Now;
_requestedBy = token._userName;
}
public Guid RequestID
{
get { return _requestID; }
}
public string RequestedBy
{
get { return _requestedBy; }
}
public DateTime WhenRequested
{
get { return _whenRequested; }
}
}
If I understand you correct it the line:
Assert.AreEqual(hostSourceID, actual.HostSourceID);
that generates the exception.
Since, this is a unit test (don't know which framework you use), you really should consider obtaining the scope when initializing the unit test and dispose it again when you finalize the unit test... In most unit test frameworks there's a place to do such stuff..
This will keep the scope alive during the unit test and you will not get this error... It is definately caused by lazy loading and the fact that the scope used to create the object is disposed.
Regards
Henrik
Additional information regarding how to use Telerik OpenAccess ORM can be found here.
Best wishes,
Dimitar Kapitanov
the Telerik team
Instantly find answers to your questions on the new Telerik Support Portal.
Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
Thank for the link. I was already aware of it, since we use MS unit test framework for our unit test.
The basic idea though is to keep the object scope alive during tests.
Cheers,
Henrik
Henrik is right. We have many tests but in the particialur case the object that is getting passed into the tested method is returning with some data removed after the scope was used in the tested method.
SInce the object was created outside the Using scope block I am not sure why some (not all) data in the object was getting trashed as it appears is happening.
Marty
The more probable scenario is that the data is not being trashed as you assume but it has never been loaded. Since OpenAccess uses the lazy loading mechanism, trying to access an unloaded data requires an object scope to manage such operation. Hence, disposing of your scope leads to the exception you are getting..
Nevertheless, you should be able to instantiate a static scope for your test class in a ClassInitialize method which runs before any of the tests have started and then dispose after all the tests have ran.
Regards,
Zoran
the Telerik team
Instantly find answers to your questions on the new Telerik Support Portal.
Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
This is how I handle IObjectscope. I am also getting an error IObjectscope is alread closed. Could you please advice the below code needs an change.
static public IObjectScope ObjectScope()
{
Database();
if (_theObjectScopeProvider._myScope == null)
{
_theObjectScopeProvider._myScope = GetNewObjectScope();
}
return _theObjectScopeProvider._myScope;
}
static public IObjectScope GetNewObjectScope()
{
var db = Database();
db.Properties.ConnectionTimeout = 0;
var newScope = db.GetObjectScope();
return newScope;
}
static public Database Database()
{
if (_theObjectScopeProvider == null)
{
_theObjectScopeProvider = new ObjectScopeProvider();
}
if (_theObjectScopeProvider._myDatabase == null)
{
_theObjectScopeProvider._myDatabase = Telerik.OpenAccess.Database.Get("OracleConnection", OpenAccessConfigurationHandler.ConfigOverride);
}
return _theObjectScopeProvider._myDatabase;
}
This code is how you obtain the IObjectScope instance. I would be interested in seeing how you are using the obtained instance. The exception indicates that you are trying to use an already dispose IObjectScope instance.
Kind regards,
Ady
the Telerik team
In server, we use structuremap something like this:
For<
IObjectScope>() .LifecycleIs(new WcfInstanceContextLifecycle())
.Add(ctx => ObjectScopeProvider.GetNewObjectScope());
WcfInstanceContextLifecycle is a custom ILifecycle for the StructureMap framework for scoping instances to the lifetime of a WCF call. This is the foundation for enabling session per request over WCF.
Thanks
Unfortunately the usage code does not tell me much. The reason for this exception is that the IObjectScope instance is already disposed when you try to use it to perform CRUD operations. Can you try and find out when the obtained scope is disposed by the StructureMap framework?
Greetings,
Ady
the Telerik team
private
static ObjectContainer Prepare(ObjectContainer container)
{
var resultContainer = new ObjectContainer();
using(var scopeBlock = ObjectScopeProvider.GetNewScopeBlock())
{
var idsToBeDistributed = container.Extent<object>() .Where(x => x.IsOf<INeedDistribution>() && IsPersistant(container, x))
.Select(x => container.GetObjectId(x))
.ToList();
var refreshedObjects = idsToBeDistributed.Select(id => scopeBlock.Scope.GetObjectById(id)).ToList();
resultContainer.CopyFrom(scopeBlock.Scope,
string.Empty,
refreshedObjects,
new FetchGroupCollector(FetchGroupCollector.DefaultFetchGroup));
}
return resultContainer;
}
definition of Objectscopeblock class:
internal
sealed class ObjectScopeBlock : IObjectScopeBlock
{
public ObjectScopeBlock(IObjectScope scope)
{
Contract.RequiresNonNullArgument(scope, "scope");
Scope = scope;
}
#region
IObjectScopeBlock Members
public IObjectScope Scope { get; private set; }
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
if (Scope == null)
{
return;
}
Scope.Dispose();
Scope = null;
ObjectScopeProvider.ResetDbConnectionTimeout();
}
#endregion
}
The code looks fine. How is the ObjectContainer that is passed into the 'Prepare' method handled. If the 'container.GetObjectId' method throws the exception the underlying scope of the container seems to be disposed.
Can you prepare a sample application that reproduces this exception? This would help in resolving the issue sooner.
All the best,
Ady
the Telerik team