This question is locked. New answers and comments are not allowed.
Hello,
i have a basic question.
My scenario is a winform backoffice application for dealing with product supplier prices.
When i do the BusinessBase.AddEntity() i see the insert into .. on he SQL Server.
My question is: why when i bind currentWine.supplierWinePrices it triggers a SELECT into my DB?
As far as i understand the scope mechanism, when i do the AddEntity() it should be updated..
How to avoid this?
BTW, AddEntity() is just:
Regards,
Rafael
i have a basic question.
My scenario is a winform backoffice application for dealing with product supplier prices.
SupplierWinePrice currentSupplierWinePrice = new SupplierWinePrice();currentSupplierWinePrice.Comment = "New Wine";currentSupplierWinePrice.LastCheckedDate = DateTime.Now;currentSupplierWinePrice.Supplier = (Supplier)radDropDownListSuppliers.SelectedValue;currentSupplierWinePrice.Wine = currentWine;currentSupplierWinePrice.Currency = currentSupplierWinePrice.Supplier.Currency;BusinessBase.AddEntity(currentSupplierWinePrice);//SuppliersradGridViewSuppliers.DataSource = null;radGridViewSuppliers.DataSource = currentWine.SupplierWinePrices;When i do the BusinessBase.AddEntity() i see the insert into .. on he SQL Server.
My question is: why when i bind currentWine.supplierWinePrices it triggers a SELECT into my DB?
As far as i understand the scope mechanism, when i do the AddEntity() it should be updated..
How to avoid this?
BTW, AddEntity() is just:
HighLevelBOModel dbContext = GetHighLevelBODBContext();
dbContext.Add(entity);
dbContext.SaveChanges();
Regards,
Rafael
18 Answers, 1 is accepted
0
IT-Als
Top achievements
Rank 1
answered on 07 Oct 2010, 04:06 PM
Hi Rafael,
No, the Add method adds the persistent object to the scope - and if you constructed (new'ed) this object previously it is inserted during SaveChanges().
To update an instance you'll have to retrieve the instance somehow (typically by Id - or other means), apply the changes to the relevant properties and do a SaveChanges()
Regards
Henrik
No, the Add method adds the persistent object to the scope - and if you constructed (new'ed) this object previously it is inserted during SaveChanges().
To update an instance you'll have to retrieve the instance somehow (typically by Id - or other means), apply the changes to the relevant properties and do a SaveChanges()
Regards
Henrik
0
Rafael
Top achievements
Rank 1
answered on 08 Oct 2010, 08:47 AM
Hi Henrik,
Let me be a little more clear.
Scenario: entity "Wine" and it can have multiple "SupplierPrices".
Winform BackOffice application, loading the full List<Wine> with a fetch plan like:
This List<Wine> is then binded to a radGridView and OnSelectionChanged() binds Wine.SupplierPrices to another radGridView.
Classic.
When i add a new SupplierPrice , doing wine.SupplierPrices.add(newSupplierWine) and then dbContext.SaveChanges() the scope gets updated and then the new infos are persisted into the DB.
Why on rebind again the current (updated) wine.SupplierPrices to the radGrid, it does another SELECT from the DB? The scope should already have the updated version.
Or.. is there any way of changing the concurency settings on a Reverse mapping scenario ?
Rafael
Let me be a little more clear.
Scenario: entity "Wine" and it can have multiple "SupplierPrices".
Winform BackOffice application, loading the full List<Wine> with a fetch plan like:
FetchStrategy fetchStrategy = new FetchStrategy();fetchStrategy.LoadWith<Wine>(c => c.Region);fetchStrategy.LoadWith<Wine>(c => c.Country);fetchStrategy.LoadWith<Wine>(c => c.Appellation);fetchStrategy.LoadWith<Wine>(c => c.SubRegion);fetchStrategy.LoadWith<Wine>(c => c.Producer);fetchStrategy.LoadWith<Wine>(c => c.WineGrappes);fetchStrategy.LoadWith<Wine>(c => c.WineType);fetchStrategy.LoadWith<Wine>(c => c.SupplierWinePrices);fetchStrategy.LoadWith<SupplierWinePrice>(c => c.Supplier);fetchStrategy.LoadWith<SupplierWinePrice>(c => c.Wine);fetchStrategy.LoadWith<Supplier>(c => c.Country);//fetchStrategy.MaxFetchDepth = 5;dbContext.FetchStrategy = fetchStrategy;This List<Wine> is then binded to a radGridView and OnSelectionChanged() binds Wine.SupplierPrices to another radGridView.
Classic.
When i add a new SupplierPrice , doing wine.SupplierPrices.add(newSupplierWine) and then dbContext.SaveChanges() the scope gets updated and then the new infos are persisted into the DB.
Why on rebind again the current (updated) wine.SupplierPrices to the radGrid, it does another SELECT from the DB? The scope should already have the updated version.
Or.. is there any way of changing the concurency settings on a Reverse mapping scenario ?
Rafael
0
IT-Als
Top achievements
Rank 1
answered on 08 Oct 2010, 08:53 AM
Ok, now it is clear to me. Thanks for elaborating on the scenario.
How do you handle the scope? Do you create a new scope each time a "request" comes into your code behind or do you have a single scope alive (and use this for all queries) while you're on the form?
Depending on what you do of the above really have impact on what is stored/cached in the L1 cache (ObjectScope cache)
Regards
Henrik
How do you handle the scope? Do you create a new scope each time a "request" comes into your code behind or do you have a single scope alive (and use this for all queries) while you're on the form?
Depending on what you do of the above really have impact on what is stored/cached in the L1 cache (ObjectScope cache)
Regards
Henrik
0
Rafael
Top achievements
Rank 1
answered on 08 Oct 2010, 08:57 AM
private static HighLevelBOModel _dbHighLevelBoContext; /// <summary>
/// Gets the DB Context fo BO Database /// </summary> /// <returns></returns> public static HighLevelBOModel GetHighLevelBODBContext() { return _dbHighLevelBoContext ?? (_dbHighLevelBoContext = new HighLevelBOModel());
}Single scope :)
0
IT-Als
Top achievements
Rank 1
answered on 08 Oct 2010, 09:23 AM
Hi Rafael,
Ok.. Thanks, that narrows it down then.
When you rebind the grid do you hit the same method you posted in the code snippet? That is, no matter how you load or reload instances you will set up the fetch group? Or do you rely on declarative data binding?
Reason why I am asking is this: If your fetch group is different on the rebind OA will probably hit the database to load the missing fields.
Another thing, there a blog post on the L1 cache.. Don't know if you have read it.
Last in this post it says something about Commit (SaveChanges) and also about week references vs strong references of objects in the L1 cache. Weak is used by default, meaning the garbage collector can grab them at any time.
On the Commit thing: I am not exactly sure about this, but I think the L1 cache is cleared during commit..
Regards
Henrik
Ok.. Thanks, that narrows it down then.
When you rebind the grid do you hit the same method you posted in the code snippet? That is, no matter how you load or reload instances you will set up the fetch group? Or do you rely on declarative data binding?
Reason why I am asking is this: If your fetch group is different on the rebind OA will probably hit the database to load the missing fields.
Another thing, there a blog post on the L1 cache.. Don't know if you have read it.
Last in this post it says something about Commit (SaveChanges) and also about week references vs strong references of objects in the L1 cache. Weak is used by default, meaning the garbage collector can grab them at any time.
On the Commit thing: I am not exactly sure about this, but I think the L1 cache is cleared during commit..
Regards
Henrik
0
Rafael
Top achievements
Rank 1
answered on 08 Oct 2010, 10:49 AM
"When you rebind the grid do you hit the same method you posted in the code snippet?" --> no
To be even more precise, after:
this is the one i want to avoid :(
To be even more precise, after:
BusinessBase.AddEntity(currentWine);
SQL Profiler sees:and then after: radGridViewSuppliers.DataSource = null;declare@p1intset@p1=1execsp_prepexec @p1output,N'@p0 nvarchar(255),@p1 datetime,@p2 nvarchar(50),@p3 datetime,@p4 decimal(20,4),@p5 int,@p6 int',N'INSERT INTO [T_SupplierWinePrice] ([Comment], [CreationDate], [Currency], [LastCheckedDate], [PurchasePriceHT], [SupplierId], [WineId]) VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6)select scope_identity()',@p0=N'New Wine',@p1='2010-10-08 11:43:32.823',@p2=N'GBP',@p3='2010-10-08 11:43:32.827',@p4=0,@p5=16,@p6=29select@p1
var list =currentWine.SupplierWinePrices.ToList();
declare @p1 intset @p1=1exec sp_prepexec @p1 output,N'@p0 int',N'SELECT b.[SupplierWinePriceId] AS COL1, b.[Comment] AS COL2, b.[CreationDate] AS COL3, b.[Currency] AS COL4, b.[LastCheckedDate] AS COL5, b.[PurchasePriceHT] AS COL6, b.[SupplierId] AS COL7, b.[SupplierId] AS COL8, b.[WineId] AS COL9, b.[WineId] AS COL10, c.[SupplierId] AS COL11, c.[CountryId] AS COL12, c.[CountryId] AS COL13, c.[CreationDate] AS COL14, c.[Currency] AS COL15, c.[IsActive] AS COL16, c.[Name] AS COL17, c.[URL] AS COL18, d.[CountryId] AS COL19, d.[CountryCode] AS COL20, d.[CreationDate] AS COL21, d.[Currency] AS COL22, d.[CurrencySymbol] AS COL23, d.[Name] AS COL24, d.[VATRate] AS COL25 FROM [T_Wine] a LEFT JOIN [T_SupplierWinePrice] AS b ON (a.[WineId] = b.[WineId]) LEFT JOIN [T_Supplier] AS c ON (b.[SupplierId] = c.[SupplierId]) LEFT JOIN [T_Country] AS d ON (c.[CountryId] = d.[CountryId]) WHERE a.[WineId] = @p0 ',@p0=29select @p1this is the one i want to avoid :(
0
Rafael
Top achievements
Rank 1
answered on 08 Oct 2010, 10:58 AM
Tried to change backend setting "Cache reference type" to STRONG and i still havethe insert + Select queries..
0
Rafael
Top achievements
Rank 1
answered on 08 Oct 2010, 11:12 AM
And just to confirm, if i change my AddEntityMethod to:
It don't get any insert/select into the DB and he scope contains the updatted entities that are correctely binded to the radgrids.
As expected.
So one aproach to avoid a lot of queries to the DB would be to do the SaveChanges only at the end of using the backoffice or on closing the form.. wich is dangerous :)
HighLevelBOModel dbContext = GetHighLevelBODBContext();
dbContext.Add(entity);
//dbContext.SaveChanges();
It don't get any insert/select into the DB and he scope contains the updatted entities that are correctely binded to the radgrids.
As expected.
So one aproach to avoid a lot of queries to the DB would be to do the SaveChanges only at the end of using the backoffice or on closing the form.. wich is dangerous :)
0
IT-Als
Top achievements
Rank 1
answered on 08 Oct 2010, 11:43 AM
Hi Rafael,
Thanks for your valuable input. Your latest post actually confirms that I thought. On Commit (or SaveChanges) the L1 cache is cleared. So it seems. One way to solve it could be to turn on the L2 cache, which works independent of the L1 ObjectScope cache.
I have used the L2 cache only in multithreaded (multi scope) environments, but I don't see why it should not work with only one scope.
Give it a whirl and I think you get what you really want.... Secondly, the L2 cache also covers statement caching.
Regards
Henrik
Thanks for your valuable input. Your latest post actually confirms that I thought. On Commit (or SaveChanges) the L1 cache is cleared. So it seems. One way to solve it could be to turn on the L2 cache, which works independent of the L1 ObjectScope cache.
I have used the L2 cache only in multithreaded (multi scope) environments, but I don't see why it should not work with only one scope.
Give it a whirl and I think you get what you really want.... Secondly, the L2 cache also covers statement caching.
Regards
Henrik
0
Rafael
Top achievements
Rank 1
answered on 08 Oct 2010, 02:06 PM
OK, i just tried activating the Level 2 cache and.. no success. still the insert/select queries..
0
IT-Als
Top achievements
Rank 1
answered on 08 Oct 2010, 02:12 PM
Hi Rafael,
This seems a bit odd.... I can understand why you see the insert, but you really shouldn't see the select.
Did you configure the L2 cache properly using (an example from the backendconfiguration section):
<l2CacheEnabled>True</l2CacheEnabled>
<l2CacheMaxObjects>10000000</l2CacheMaxObjects>
<l2QueryCacheEnabled>True</l2QueryCacheEnabled>
<l2QueryCacheMaxQueries>10000</l2QueryCacheMaxQueries>
<ext.cache-strategy>yes</ext.cache-strategy>
and then on each object you want in the cache (app.config of your model assembly - the mappings section)
<class name="MyClass">
<extension key="cache-strategy" value="all" />
instead of "all" you could use what you want here.
Regards
Henrik
This seems a bit odd.... I can understand why you see the insert, but you really shouldn't see the select.
Did you configure the L2 cache properly using (an example from the backendconfiguration section):
<l2CacheEnabled>True</l2CacheEnabled>
<l2CacheMaxObjects>10000000</l2CacheMaxObjects>
<l2QueryCacheEnabled>True</l2QueryCacheEnabled>
<l2QueryCacheMaxQueries>10000</l2QueryCacheMaxQueries>
<ext.cache-strategy>yes</ext.cache-strategy>
and then on each object you want in the cache (app.config of your model assembly - the mappings section)
<class name="MyClass">
<extension key="cache-strategy" value="all" />
instead of "all" you could use what you want here.
Regards
Henrik
0
Rafael
Top achievements
Rank 1
answered on 08 Oct 2010, 02:16 PM
I'm using Q2 version qith rlinq models.. I've used the UI Wizards. Where do i find those settings strings?
my entities project app.config only contains connection strings
my entities project app.config only contains connection strings
0
IT-Als
Top achievements
Rank 1
answered on 08 Oct 2010, 02:18 PM
Sorry Rafael,
Don't know exactly where to point you in an rLinq model/project to find those properties.
Can anyone from Telerik elaborate?
Regards
Henrik
Don't know exactly where to point you in an rLinq model/project to find those properties.
Can anyone from Telerik elaborate?
Regards
Henrik
0
Rafael
Top achievements
Rank 1
answered on 11 Oct 2010, 11:28 AM
Someone..help?? :)
0
Hello Rafael, Henrik
You are correct, after SaveChanges is performed, the L1 cache is cleared. This is done so that after the call all of the objects have the latest values. If it was not, you could end up in a situation where you have persisted a change to the database, however the objects you have are outdated (the database values have changed but were not in the L1 cache). And we cannot implement a mechanism for reverse updates (meaning updating the entities in the L1 cache with the database values when a save is made) because this would mean updating all of the scopes connected to this thread and all the entities which could result in a big overhead. These are the reasons for clearing the L1 cache.
As to your case, if this is of critical importance I would suggest handling the loading of these SupplierPrices by yourself in-memory and not using the property on your persistent object, and thus not using the lazy loading.
The second level cache you can easily adjust the setting in the Backend Configuration dialog. As to the class specific setting cache-strategy in the designer you can select a class in the diagram, press F4 and from the Properties pane change the Cache Policy property to adjust the second level behavior for this specific class. You should know however that using the second level cache with the new designer has not yet been tested thoroughly and might be further developed post Q3.
Overall if this proves to not be too be essential to your application I would suggest leaving it doing an extra query.
I do hope this helps and please do not hesitate to contact us back if you need further assistance.
Kind regards,
Serge
the Telerik team
You are correct, after SaveChanges is performed, the L1 cache is cleared. This is done so that after the call all of the objects have the latest values. If it was not, you could end up in a situation where you have persisted a change to the database, however the objects you have are outdated (the database values have changed but were not in the L1 cache). And we cannot implement a mechanism for reverse updates (meaning updating the entities in the L1 cache with the database values when a save is made) because this would mean updating all of the scopes connected to this thread and all the entities which could result in a big overhead. These are the reasons for clearing the L1 cache.
As to your case, if this is of critical importance I would suggest handling the loading of these SupplierPrices by yourself in-memory and not using the property on your persistent object, and thus not using the lazy loading.
The second level cache you can easily adjust the setting in the Backend Configuration dialog. As to the class specific setting cache-strategy in the designer you can select a class in the diagram, press F4 and from the Properties pane change the Cache Policy property to adjust the second level behavior for this specific class. You should know however that using the second level cache with the new designer has not yet been tested thoroughly and might be further developed post Q3.
Overall if this proves to not be too be essential to your application I would suggest leaving it doing an extra query.
I do hope this helps and please do not hesitate to contact us back if you need further assistance.
Kind regards,
Serge
the Telerik team
Do you want to have your say when we set our development plans?
Do you want to know when a feature you care about is added or when a bug fixed?
Explore the
Telerik Public Issue Tracking
system and vote to affect the priority of the items
0
IT-Als
Top achievements
Rank 1
answered on 12 Oct 2010, 08:06 AM
Hi Serge,
Thanks for joining in. What you say about the L1 cache makes sense and mimics exactly what I had in mind.
But, I still think that in Rafael's case the L2 cache will do what he needs - not performing the second select
Regards
Henrik
Thanks for joining in. What you say about the L1 cache makes sense and mimics exactly what I had in mind.
But, I still think that in Rafael's case the L2 cache will do what he needs - not performing the second select
Regards
Henrik
0
Rafael
Top achievements
Rank 1
answered on 13 Oct 2010, 10:44 AM
Thanks for your anwsers!
I wasn't able to have the L2 cache running correctely, perhaps on Q3?
Anyways, i'll try to handle this situation with adding the updated/created entities to the scope but saving changes in a more global level like on window closing or something like that.
Regards,
Rafael
I wasn't able to have the L2 cache running correctely, perhaps on Q3?
Anyways, i'll try to handle this situation with adding the updated/created entities to the scope but saving changes in a more global level like on window closing or something like that.
Regards,
Rafael
0
Hi Rafael,
Serge
the Telerik team
I am sorry we were not able to help you to the fullest but I am glad you have found a suitable workaround, I will make sure that when we do provide full support and investigate the issue further I will notify you in this thread.
All the best,Serge
the Telerik team
Do you want to have your say when we set our development plans?
Do you want to know when a feature you care about is added or when a bug fixed?
Explore the
Telerik Public Issue Tracking
system and vote to affect the priority of the items