Hello everybody, First of all, I want to thank the creators of DataObjects.Net. I have only recently started to put my hands on it and I am quite satisfied. Regarding the reason of this post: I am doing some tests in order to get confident with this ORM framework. Although I don't know how to implement a certain "feature", which is common to the most of my applications. Please consider the following example: tblCompany <--- it's the table with the list of companies <fields...> tblCompanyDataChange <---- table that stores information that can be changed and need to be tracked in time. <fields..> With my previous implementation (not using DO.NET), I used to Load the Company, and during its loading I used to get only the first CompanyDataChanged associated with it. To make you better understand, I am going to quote here a short-version of the query that was used:
Now, I am trying to achieve the same result by using DataObjects.NET, and here comes my troubles. I have created a TCompany object and a TCompanyChangedData object.
Ok, as you can see: I would like the object to be transparent to the user. The user should just know that in the object TCompany there is an "ID" and - say - a "CorporateName". However, when a user wants the CorporateName, the system should look up the TCompanyChangedData Collection and get just the very first one for the given company. On the other way, when a user wants to change a CorporateName, the system should create a new CompanyChangedData, copy all the information from the previous one across but the CorporateName, and then add it to the collection... Now, I don't know if this is possible and I don't know which one is the best way to get this done. Could someone advice me (guide me ;) ) on this? Thanks in advance, Gianluca This thread was imported from our support forum. The original discussion may contain more detailed answer. Original topic by gianluca. |
Alex (Xtensive) wrote:The main advice is: since current version of object is required in most of cases, I recommend you to duplicate the fields from TCompanyChangedData in TCompany. Getting additional query or join in almost any case is enough expensive, and this solution allows to avoid this. Now - more interesting part: such things as TCompanyChangedData can be implemented in DO4 in very generic way: 1. There is Session.OperationCompleted event providing IOperation object describing the operation. All integrated operations, such as property setting, are already described there, + moreover, the operation logging framework is open, so you can create your own ones. Note that Operations framework is not fully finished yet (we plan to add more features there, e.g. undo support), but it is already used by DisconnectedState to maintain its operation log (in fact, DisconnectedState just subscribes to this event + few more related to transactions). There is no part inManual covering Operations framework now. If you're interested, open Xtensive.Storage solution and look for SessionBound.OpenOperationContext method usage.
See http://goo.gl/JYFo - there is a bit more comprehensive description. And see the first answer there - you avoid referential integrity constraints in audit tables. In DO4 this is achieved by applying [Association(OnTargetRemove = OnRemoveAction.None)] on reference property (= no FK will be created for it, and no reference fixup action will be performed on target removal).
P.S. Most likely we'll provide a generic framework for audit trail (and, likely, even undo-redo) in future. But for now this isn't scheduled. Alex (Xtensive) wrote:Forgot to add: I recommend you to store change data inside audit record in non-relational structures (e.g. as IChangeSet TChangeData<t>.Changes storing the actual data in persistent private byte[] SerializedChanges field). Likely, you won't query for it, i.e. it's just for history & recovery, so it's much easier to store it inside regular .NET objects. Alex Kofman wrote:I'd suggest you to add persistent reference from Company to last (actual) DataChange. It will allow to operate with versioned data more effectively:
Note, that by default you can not use CorporateName in LINQ queries, you can just do following:
If you want to write such queries
you need to use some advanced method described here. gianluca wrote: Thank you very much! I'll follow your advice. Gianluca. I just made a port about audit logging with DO4: http://blog.alexyakunin.com/2010/03/sim ... -some.html |