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 Mindscape team, We will be using Lightspeed for our product, but have some architecture doubts for our system’s usage of Lightspeed. So we would like to exchange some thoughts with you what can be done now (or in the future) with Lightspeed in the below respect. We have a certain type of software in which we develop a common base solution. For different implementations/projects this base solution is than tweaked/expanded depending on special requirements for that certain project/customer. This also sometimes applies to the database model and ORM model (i.e. adding columns, extra tables, validation). Now, I would like to have a small discussion about possibility to have “base Lightspeed model” in one solution/dll and have an “inherited Lightspeed model” for expansion in another dll. I am somewhat aware of the limitations (partial classes only possible in one dll) and (im)possibility of this, but am looking for ideas how to get with Lightspeed most near to that ideal design/solution. Thanks for your time |
|
|
This depends on exactly what you want out of LightSpeed (runtime vs design time) and how the models relate. At runtime, you can inherit across assembly boundaries with no problem. Columns from base types are inherited into derived types. Depending on the nature of the model, this could be done using either single table inheritance or concrete table inheritance. However, designer support for this scenario is limited. You can use external type definitions to specify that an entity type derives from a class that is not present in the model -- in your case, an entity in another model -- but external types are ignored for the purposes of designer-database synchronisation so it will prevent you from using that feature on the derived classes. (If you are using STI it will also prevent you from using that feature on the base class.) More difficult is if you need associations between entities in the "inherited model" and entities in the "base model." Associations in LightSpeed are always bidirectional. So if Entity E1 in Assembly A1 has an association to Entity E2 in Assembly A2, then A1 depends on A2; but E2 must have a reverse association to E1, so A2 also depends on A1. We have a circular dependency and disaster ensues. One way around this is to declare only the foreign key field, not the association, and then create your own methods to load the associated entity/entities by ID or by FK queries when required, though you will still need to figure out some way to break the circular dependency (e.g. weak-typing the methods in the depended-on assembly and providing strong-typing wrappers in the depending assembly). Another possibility is to say that if we have to associate A1.E1 and A2.E2 then we will instead create a vacuous derived class of E2 in A1, and associate them: i.e. A1.E1 is associated with A1.E2, where A1.E2 derives from A2.E2 and adds no properties of its own (except of course the association to A1.E1). This is probably the easiest solution to use but may require a bit of care to set up and maintain. I would also strongly advise prototyping before committing to this design, so as to ensure that you don't run into any issues with the combination of inheritance and associations (you should be okay as long as all the associations are to the derived class A1.E2 and none to the CTI base class A2.E2, but this may prove to be an unacceptable constraint, though it could possibly be resolved by making the inheritance STI-based on a vacuous column -- prototyping will reveal whether this is a real issue for your model or not). You also mention validation. Declarative validations are inherited, but cannot be tweaked: e.g. if BaseEntity.Name is constrained to be less than 100 characters, then you can't change it in DerivedEntity to allow it to be 120 characters instead. If you have a requirement like this you need to custom-code it in an OnValidate override. These are some initial thoughts: very happy to continue this discussion if you have further questions, or want to explore the details, or have suggestions on how we can make this easier (acknowledging of course that there may be technical limitations which prevent us doing all we would like!). |
|
|
Ivan thanks for an exhaustive answer. Yes, it does sound tricky to implement and maintain. I am also considering to focus on a simpler variant - covering the situation of expanding a table (adding columns) in derived model, and having nothing extra (new tables, association) in the derived model, similar to your example. "Base model" (and database design) would have all entities and associations, and some tables (vacous) would be expandable in the "Derived model". I.e. "Base model" would have unchangable "Item" and vacous "ItemDetails" table with a 1:1 relation. The "Derived model" would have "ItemDetails" with the needed columns for the project. I am not sure in your example of A1.E2 deriving from A2.E2... Are you considering that the base model (A1) should at runtime load the derived model (A2) and then specify that inheritance? Sure, I would need to prototype and see how this would acutally be used. |
|
|
One thing to watch out for is that associations to base classes are supported ONLY with single table inheritance. Assuming you want to use concrete table inheritance, all associations must be between leaf classes. In my example of vacuous derivation (creating an A1.E2 that derives from A2.E2), sorry, this may not have been clear: A1 is the *derived* model, so A1.E2 inherits from A2.E2. All the associations and the inheritance are declared in A1 (which contains the derived classes), and A1 has a reference to A2 (which contains the base classes). You certainly don't want to have the base model needing to load the derived model at runtime. Re copying source between projects, don't forget you can use Visual Studio's Add Existing Item > Add as Link feature to share source without having to remember to copy the source files every time you make a change. So one way to break the circular dependency issue is for each project to have its own derived .lsmodel, but also the shared base .lsmodel added as a link. You still have the other issues but at least this avoids the circular dependency between assemblies. |
|