I have an entity [Test]. It has many fields. These fields store huge data. (I use many CLOB, which is seralized to many [Transient fields]). In my application I need to show in a Grid a list of these tests (I show only Name and Date). But if I load all of tests from DB - my application require more and more memory. I want to load from Tests only Name and Date fields at first (and maybe pk Nr also). This info is enough to show in Grid. And then user select one Test and analyse it (analyse all necessary data). And now I need load all data for concrete Test. After user commit this Test - I need free memory of it in scope.
So, How I can clear all info about loaded/commited Test from scope?
5 Answers, 1 is accepted
To lazy load fields, you have to set the strategy to 'Lazy'. If you use the designer, just select the property and change it in the property window.
If you have a situation where you need more data immediately, please use the FetchStrategy to optimize the generate sql statements.
To free the memory, you have to dispose the scope. We are trying to keep our caches small by using weak references but you never know when the memory is freed.
All the best,
Jan Blessenohl
the Telerik team
Thank you for being the most amazing .NET community! Your unfailing support is what helps us charge forward! We'd appreciate your vote for Telerik in this year's SQL Server Community Awards. We are competing in TWO categories and every vote counts! VOTE for Telerik NOW >>
my Entity:
public class TestGen : IInitializeTransients { [FetchField("fgTestGen")] private string name; public string Name { get { return name; } set { name = value; } } [FetchField("fgTestGen")] private DateTime testBegin; public DateTime TestBegin { get { return testBegin; } set { testBegin = value; } } public string CLOBData{get;set;} // it is a CLOB-field //.... } FetchPlan.cs:
public class FetchPlans { public static FetchPlan fpTestGen = new FetchPlan( new string[] { "fgTestGen"}, FetchPlan.DefaultMaxDepth, FetchPlan.NoLimit ) ; }ScopeProvider.cs:
static public IObjectScope ObjectScope() { // ... scope.FetchPlan.Clear(); scope.FetchPlan.Add("fgTestGen"); scope.FetchPlan.MaxDepth = 3; return scope; }but when I load TestGen from db:
var result = from p in scope.Extent<TestGen>() select p; Also InitializeTransient-methods are called too. I don't need it too.
What I do incorrect?
Thanks!
You are using the debugger ;)
Our lazy loading code is injected into your properties, this means if the debugger shows the content of the properties in the watch window, the data is loaded. To see the real situation you have to switch off property evaluation in the Tools->Options->Debugging window.
Kind regards,
Jan Blessenohl
the Telerik team
Thank you for being the most amazing .NET community! Your unfailing support is what helps us charge forward! We'd appreciate your vote for Telerik in this year's SQL Server Community Awards. We are competing in TWO categories and every vote counts! VOTE for Telerik NOW >>
If I switch off property evaluation in the Tools->Options->Debugging window - I can't see even my FetchFields!
Where I have to see and check - my FetchFields are initialized, but others - not. ??
You are right, analyzing loaded fields if you use auto puberties is complected. I have written two static functions that you can call in your debugger or in your application to print the field status to console or to the debugger windows:
private static void DumpLoadedFieldsConsole(Object obj){ var ret = GetLoadedFields(obj); foreach (var t in ret) { if (t.Item2) Console.WriteLine("Field: " + t.Item1 + " is loaded."); else Console.WriteLine("Field: " + t.Item1 + " is notloaded."); }}private static void DumpLoadedFieldsDebugger(Object obj){ var ret = GetLoadedFields(obj); foreach (var t in ret) { if (t.Item2) System.Diagnostics.Debug.WriteLine("Field: " + t.Item1 + " is loaded."); else System.Diagnostics.Debug.WriteLine("Field: " + t.Item1 + " is notloaded."); }}private static List<Tuple<string, bool>> GetLoadedFields(object obj){ var ret = new List<Tuple<string,bool>>(); var pc = obj as Telerik.OpenAccess.SPI.dataobjects.PersistenceCapable; var pmp = pc.OpenAccessEnhancedGetPersistenceManager(); // call OpenAccessRuntime.DataObjects.PMProxy.getRealPM return OpenAccessRuntime.DataObjects.OpenAccessPersistenceManagerImp var runtimeAssemly = AppDomain.CurrentDomain.GetAssemblies().Where(x => x.FullName.StartsWith("Telerik.OpenAccess.Runtime,")).Single(); var pmpType = runtimeAssemly.GetTypes().Where(x => x.FullName == "OpenAccessRuntime.DataObjects.PMProxy").Single(); var method = pmpType.GetMethod("getRealPM"); var pm = method.Invoke(pmp, null); // OpenAccessRuntime.DataObjects.OpenAccessPersistenceManagerImp.GetInternalStateManagerNoException returns OpenAccessRuntime.DataObjects.PCStateMan var pmImpType = runtimeAssemly.GetTypes().Where(x => x.FullName == "OpenAccessRuntime.DataObjects.OpenAccessPersistenceManagerImp").Single(); method = pmImpType.GetMethod("GetInternalStateManagerNoException"); var stateMan = method.Invoke(pm, new object[] { pc }); // access OpenAccessRuntime.DataObjects.PCStateMan.state return OpenAccessRuntime.common.State var stateManType = runtimeAssemly.GetTypes().Where(x => x.FullName == "OpenAccessRuntime.DataObjects.PCStateMan").Single(); var field = stateManType.GetField("state", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); var state = field.GetValue(stateMan) as OpenAccessRuntime.common.State; var cmd = state.getClassMetaData(); foreach (var fmd in cmd.fields) { var loaded = state.containsField(fmd.stateFieldNo); ret.Add(new Tuple<string,bool>(fmd.PropertyName??fmd.name,loaded)); } return ret;}You have to add a reference to the Telerik.OpenAccess.Runtime assembly.
Best wishes,
Jan Blessenohl
the Telerik team
Thank you for being the most amazing .NET community! Your unfailing support is what helps us charge forward! We'd appreciate your vote for Telerik in this year's SQL Server Community Awards. We are competing in TWO categories and every vote counts! VOTE for Telerik NOW >>