This thread looks to be a little on the old side and therefore may no longer be relevant. Please see if there is a newer thread on the subject and ensure you're using the most recent build of any software if your question regards a particular product.
This thread has been locked and is no longer accepting new posts, if you have a question regarding this topic please email us at support@mindscape.co.nz
|
Hi, I just tried transient class in modal designer: 1) Create an entity named DbObject with some properties, with Transient=True I have some questions: 1) Is it true that transient means the object not persistent in database? 4) Finally the question: How to use transient class? Any wrong with my approach? Thanks in advanced. |
|
|
1. Correct, transient classes are not persisted in the database. It is rare to use transient classes at all because if the class doesn't want to be in the database then why does it need to be a LightSpeed Entity -- why not make it a Plain Old CLR Object? Transient classes were added because some customers wanted to use LightSpeed validation on non-persistent objects, and that's about the only scenario where they're useful. 2. Discriminators are essentially meaningless when inheriting a transient class, because the point of a discriminator is to tell LightSpeed what kind of object to instantiate when it loads things from the database -- which will never happen with a transient class. Nevertheless, discriminators are a formal requirement of entity derivation in LightSpeed: if you want to participate in the Entity system, and you want to be a derived class, you need to have a discriminator. 3. Ah, but you *are* using a DbObject, because a DbCodeName *is* a DbObject. And because inheritance in LightSpeed is modelled in the database as single-table inheritance, LightSpeed expects to load derived objects from, and store derived objects in, a table named for the ultimate base class. In your case, DbObject is the ultimate base class, so LightSpeed expects to store DbCodeName entities in the DbObjects table (which will have an appropriate discriminator column). The same will apply to any other entity which ultimately derives from DbObject. But the DbObjects table doesn't exist, so the attempt to save a DbCodeName fails. 4. As mentioned above, transient classes are primarily for objects that want to use LightSpeed entity facilities such as validation without being persisted. So your usage of a transient class as a base class for persistent classes is not advisable. It doesn't really make sense to say to LightSpeed, "if you see a Contribution, don't store it, but if you see a VideoContribution or AudioContribution, do store it," because VideoContributions and AudioContributions *are* Contributions! There are two possible remedies for this, depending on what you are trying to achieve by marking DbObject as transient. * If your intent is that there shouldn't be any instances of the "raw" DbObject class, but only of derived classes, then mark DbObject as abstract. You can't do this directly in the designer, but you can do it through a partial class declaration. * If your intent is that the base DbObject fields should not be stored, but only the additional fields added by derived types, then mark the individual fields as transient. Note that the discriminator must not be transient. In either case you will still need a DbObjects table because that is the nature of single-table inheritance -- objects from anywhere in the hierarchy are stored in the same table, whose columns are the union of these objects' properties, with a discriminator to distinguish the different types. Hope this clarifies things! |
|
|
Hi, Ivan, What I want is to have a basic class with some common handling and properties. My thought is: DbObject, Transient <- DbCodeName <- Department, Work Group ... I understand your implementation, but I still think it's something conflict: transient class is not persistent according to definition, but it has to be persistent if I use it as base class. I try to mark DbObject as abstract but it's removed by designer every time if there is a change. Any better idea to implement my thought with LightSpeed? Thanks,
|
|
|
I think I see what you are getting at -- you want to put common helper methods into a base class, but that base class doesn't have any persistent data of its own -- it's just a way of adding some methods to the Entity<T> class. So you don't actually want to use single-table inheritance at all: you just want somewhere to centralise some standard bits. Is that correct? The good news is that you can do this; the bad news is that it's not supported in the designer. The designer assumes that you are always creating "real" entities and that inheritance is always modelled as single-table inheritance (with a discriminator). I'll have a look at adding designer support for this scenario if it's what you're trying to achieve -- let me know. In the meantime, one possibility to consider is using extension methods on Entity to provide your additional logic. However these will not allow you to add (transient) state. Re marking a generated class as abstract, what you need to do is create your own .cs file with a partial class declaration in it, and apply the abstract modifier there: Because this is in your .cs file, rather than in the generated .cs file, it won't get overwritten, but the C# compiler will still fold it into the class definition at compile time. However, if I understand your requirement, this probably won't help with what you're wanting to do. |
|
|
Hi, Ivan, I would like to clarify my thought of DbObject: 1) For common properties, i.e. CreatedBy, CreatedOn property ..., then I don't need to define in each entity 2) For common logic, i.e. audit trail for insert/update/delete in OnSaving ... 3) For common helper methods, as you said Please kindly advice if you think there is better approach with LightSpeed. Thanks,
|
|
|
What you describe is entirely appropriate and will work, with the following observations and caveats: 1. If you want to have persistent properties (e.g. CreatedBy) declared in a base class (but persisted via the derived class), you MUST NOT mark the base class as [Transient]. Transient tells LightSpeed not to persist ANY of the properties in this class. You can still mark individual properties of the base class as [Transient] if you don't want them persisted. 2. If you need LightSpeed to take care of polymorphism, e.g. you want to call Find<Contribution> and have LightSpeed figure out whether any given row is a VideoContribution or an AudioContribution, then you must use single table inheritance with a discriminator. This is the scenario supported by the designer. 3. If you are not loading entities polymorphically through the DbObject base class, then you can put each entity type in its own table, and you do not need a discriminator. This scenario is not currently supported by the designer; you would have to write the entity declarations by hand in C# or VB. I have logged a feature request to support this in the designer. In either of cases 2 and 3, you can add common logic such as an OnSaving override or helper methods in the base class as per your requirements 2 and 3. If you are using the designer (i.e. the polymorphic/STI scenario), you will do this by extending the generated base class using a partial class declaration. If you are writing the declarations by hand then you do not need a partial class. I believe your scenario is #3, i.e. you do not want single-table inheritance and you do not need polymorphism through DbObject -- it is as you say just providing common state and services. Can you confirm that you will be having separate tables for each entity type (not a DbObjects table) and that you do not require LightSpeed to load entities polymorphically i.e. you do not need to be able to go Find<DbObject>(...)? This will help us to prioritise the designer work for scenario #3. Thanks! |
|
|
Hi, Ivan, You get me exactly, #3 is just what I want. And answers for your questions: Thanks,
|
|
|
This has now been added to the designer and will be in the next nightly build. Simply select the inheritance arrow and change the Inheritance Type from SingleTableInheritance to ConcreteTableInheritance. (Terminology taken from http://martinfowler.com/eaaCatalog/concreteTableInheritance.html.) LightSpeed will then (a) stop asking you to supply a discriminator and (b) leave out the [Discriminator] attribute in the generated code, so that each entity type is "on its own" when it comes to the database table (as shown in the diagram in the link above). Once again, we would still recommend that you do not mark the base class as Transient, but rather mark individual base class properties as Transient if you do not want them persisted. |
|
|
Hi, Ivan, Thanks for so prompt action. I'll try it after I get the nightly build. One more question: is "Update Database" function support ConcreteTableInheritance? (As dicussed in my last post, SingleTableInheritance is not supported in current version) Thanks, |
|
|
No, Update Database is still not supported for any form of inheritance. Sorry! |
|
|
Hi, Ivan, It's ok for me. But I'll look forward to the support :). Thanks,
|
|