Using Transaction from TSQLQuery property lazarus / 16-Databases ---------------------------------------------------------------------- fpcoder · 2014-03-08 12:24 Why doesn't this work: Query.Transaction.RollbackRetaining Shouldn't that be the same as calling: Transaction.RollbackRetaining ? ---------------------------------------------------------------------- taazz · 2014-03-08 12:33 only if query.transaction = transaction ---------------------------------------------------------------------- Zoran · 2014-03-08 15:37 Quote from: kapibara on March 08, 2014, 01:24:24 pmWhy doesn't this work: Query.Transaction.RollbackRetaining Shouldn't that be the same as calling: Transaction.RollbackRetaining ? TSQLQuery only publishes property Transaction inherited from TDBDataset, but this property is still of type TDBTransaction, as defined in TDBDataset, not TSQLTransaction. Now, TSQLTransaction descends from TDBTransaction, so you can (and should) set your SQLQuery's Transaction to some SQLTransaction. But, still you cannot use RollbackRetaining method directly, as it is not defined in TDBTransaction, but only in TSQLTransaction. That is why compiler will encounter error on line Code: [Select]Query1.Transaction.RollbackRetaining;, but you can cast: Code: [Select]TSQLTransaction(Query1.Transaction).RollbackRetaining; will work. ---------------------------------------------------------------------- fpcoder · 2014-03-09 18:08 Thanks! Casting works fine, even like this: with aQuery.Transaction as TSQLTransaction do   RollbackRetaining; Is there a reason why casts are necessary? I guess TSQLQuery in theory could make more properties from TSQLTransaction available? ---------------------------------------------------------------------- Zoran · 2014-03-09 21:18 Quote from: kapibara on March 09, 2014, 07:08:32 pmIs there a reason why casts are necessary? I guess TSQLQuery in theory could make more properties from TSQLTransaction available? Casts are necessary because property Transaction is not of type TSQLTransaction, but it is of type TDBTransaction. Please keep in mind that this code with cast is not safe, this code relies on that the programmer knows that the Transaction is TSQLTransaction, but the compiler cannot know that. The property Transaction is of type TDBTransaction and, because TSQLTransaction descends from TDBTransaction, it might be TSQLTransaction. With casting, you take the responsibility to ensure that this Transaction is TSQLTransaction. You might want to take safer approach: Code: [Select]if Query1.Transaction is TSQLTransaction then   TSQLTransaction(Query1.Transaction).RollbackRetaining; ---------------------------------------------------------------------- mangakissa · 2014-03-10 08:38 How can you check on Query1.Transaction is TSQLTransaction if Query1.Transaction is always TDBTransaction. The above code could not work. ---------------------------------------------------------------------- taazz · 2014-03-10 08:58 Have you tried it? If not why not? ---------------------------------------------------------------------- Zoran · 2014-03-10 10:41 Quote from: mangakissa on March 10, 2014, 09:38:06 amHow can you check on Query1.Transaction is TSQLTransaction if Query1.Transaction is always TDBTransaction. The above code could not work. You are wrong, TSQLTransaction descends from TDBTransaction. It is of course quite normal to assign an instance of a child class to a variable (or property) declared as its parent class. Quote from: taazz on March 10, 2014, 09:58:42 amHave you tried it? If not why not? Of course he had not tried it. ---------------------------------------------------------------------- fpcoder · 2014-03-10 18:23 Zorans example works, but it uses a query directly. What I actually wanted was to call RollBack using the DataSet variable from AfterPost. Like this: with DataSet.Transaction do   RollBack; I tried this because the compiler complains that DataSet is not used in AfterPost etc. But DataSet can't be used because properties and functions are not exposed? Should there be some code added to TSQLQuery to make things more accessible? Casts like these makes DataSet.Transaction accessible, but then two cast are necessary. One for the DataSet and then also one for the Transaction. Examples:   if DataSet is TSQLQuery then     with DataSet as TSQLQuery do       if Transaction is TSQLTransaction the         with Transaction as TSQLTransaction do           Rollback;   if TSQLQuery(DataSet).Transaction is TSQLTransaction then     with TSQLQuery(DataSet).Transaction as TSQLTransaction do       Rollback; For now I put a silencer on the DataSet variable and call: Transaction.Rollback But this way the programmer must know what Transaction belongs to what Query. ---------------------------------------------------------------------- taazz · 2014-03-10 18:33 you are kidding me right? Here use these 2 procedures Code: [Select]procedure CommitQuery(const aDataset:TDataset; aRetain :Boolean = true); inline; begin   if (aDataset is TSQLQuery) and (TSQLQuery(aDataset).Transaction is TSQLTransaction) then begin     if aRetain then TSQLtransaction(TsqlQuery(aDataset).Transaction).CommitRetaining     else  TSQLtransaction(TsqlQuery(aDataset).Transaction).Commit;   end; end; procedure RollBackQuery(const aDataset:TDataset; aRetain :Boolean = true); inline; begin   if (aDataset is TSQLQuery) and (TSQLQuery(aDataset).Transaction is TSQLTransaction) then begin     if aRetain then TSQLtransaction(TsqlQuery(aDataset).Transaction).RollBackRetaining     else  TSQLtransaction(TsqlQuery(aDataset).Transaction).RollBack;   end; end; use those, your code will remain clean of typecasts. ---------------------------------------------------------------------- mangakissa · 2014-03-10 18:41 Quote from: ZoranOf course he had not tried it. I  just did. This topic gave met the same answer [url http://forum.lazarus.freepasc al.org/index.php/topic,22626.msg133811.html#msg133811[/url] I'm sorry that I doubted. Sometimes is typecasting very confusing. ---------------------------------------------------------------------- fpcoder · 2014-03-11 16:57 Its clear then that casts are necessary and the question is answered. Thanks for the examples. Maybe some polymorphism magic in the database components could remove the need for casts. But casts are a small price to pay so its not a big deal.