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 all, I'm in the process of updating our model from LS1 to LS2. I have all my tables mapped with my associations. I have a couple of entities that currently have two one to one associations with each other. A user has a fk to a spider (fk on the spider table) and another fk to spider (same, fk on spider table). I've imported everything with the LS GUI, but I'm having issues getting the one to one working. I'm getting error messages such as "Entity User has multiple properties/associations named 'Spiders' C:\development\WebModel\Model\SpiderTracksModel.lsmodel 0 1 WebModel". I'm not sure how to fix this via the editor, but our DB is fine as all of the classes we have defined from our 1.x implementation work prefectly. How do I edit these associations in the editor to fix these problems?
Thanks, Todd |
|
|
I'm assuming from your description that what you've done is drag the User and Spider tables onto the design surface, right? In this case LightSpeed has created a one-to-many association for each foreign key. So you have two associations between User and Spider, and at the User end both of these are called Spiders. You need these to be one-to-one associations with different names. Is that correct? If so: * To convert them into one-to-one associations, right-click the association arrow and choose Convert to One-to-One Association. * To change the name of one end of the association, click the association arrow and edit the name in the Properties grid. I'm not sure offhand whether you'll need to edit the Source or Target of the one-to-one association but it should be pretty clear because it'll be the one called "Spider" or "Spiders"! That should see you right -- let us know if it doesn't. |
|
|
Thanks for the speedy reply Ivan. This works for the first relationship, but it doesn't work for the second. In the second entity I receive the error "Can not establish link of type OneToOneAssociation between elements... since there is already a link of this type between elements and link's domain relationship has AllowDuplicates = false". I'm not quite sure why I'm getting this as I've renamed both collections on the user side from "Spiders" to CurrentlyAllocatedToUser and ActiveTextMessageUser. The names are unique as are the BackReference column names, so I'm not sure why I can't have 2 differently named 1 to 1 references between Entities. Any ideas how to get around this? |
|
|
This is a (very stupid) bug in the designer. There'll be a fix in the next nightly build. Apologies for the inconvenience. |
|
|
No worries. I'll install the nightly build of the IDE and just use the release DLL for the runtime. |
|
|
Sorry for the double post, but we use the Enterprise version. Where can I get the nightly build for it?
|
|
|
(Sigh) nevermind, I found it. Just call me the spam king! |
|
|
Hi Ivan, I've just installed the latest nightly gui, but it appears to generate different code the the release version. Is there a place I can view the generated C# code? I'd like to manually compare it to our classes now to make sure everything is the same.
Thanks, Todd |
|
|
Yes, you should be able to expand the .lsmodel file in Solution Explorer to see the generated .cs file. If that doesn't work, just open the folder containing the .lsmodel file in Explorer or a command prompt, and look for a file with the same name as the .lsmodel but a .cs extension. |
|
|
I have that class, but all that is defined within it is the SpidertracksModelUnitOfWork class, it doesn't have any of my entities in it. I also have warnings that my old classes I've made partial only have a single part, so it seems the project isn't picking up the generated entities. |
|
|
Did you uninstall the 2.2 RTM before installing the nightly? We have a known issue with this scenario which can cause this symptom. Could you check Control Panel for installed instances of LightSpeed (you may see more than one), uninstall them, and then reinstall the nightly and let us know if the problem persists? Thanks! |
|
|
That fixed my problem with the generation, thanks for doing that. Now I have a few other questions.
We use custom validations that extend the LS ValidationAttribute class and add an integer code. This allows us to translate error codes into multi langauge when our pages render. Is it possible to override the generated validation and use our class with 3 arguments (int min, int max, int errorCode)?
We have over 50 tables and entities which we've broken down in to sub namespaces of WebModel.Model. For instance we have WebModel.Model.ReferenceData, WebModel.Model.TextMessage etc. Can I override the generated namespaces on classes?
Thanks, Todd |
|
|
You can specify custom validations by opening the model explorer (View > Other Windows > LightSpeed Model), locating the property, right-clicking and choosing Add New Custom Validation. This isn't the most convenient if you're using the validation everywhere and the validation is essentially just a custom implementation of a standard one (e.g. range validation). If this is the case, you may be able to work around it using a custom template; let me know more details and I'll see if we can suggest a better approach. You can't directly override the generated namespaces: the provided code templates put all entities in a model into the same namespace. You could do this with a combination of custom templates and extension properties. This is moderately ninja stuff but by no means impossible; I'd be happy to guide you through it if required. |
|
|
The help would be greatly appreciated! We'll be using it in pretty much every length validation, so replacing the default attributes would be helpful. I tried the custom tool, but it generated the code on the Property, not the instance variable itself. This is what we currently have in our model. public partial class Organisation : BaseEntity ... }
I'd also apprecaite some pointers on how to mod the tool so I can override the namespace on different entities.
Thanks Todd |
|
|
The code generation templates are plain text files, installed into Tools > Designer > C# > Templates. There are two ways of customising them to generate your own code. 1. Edit these files in place. This will customise the code for *every* LightSpeed project on the machine, but (a) your changes will get overwritten when you reinstall LightSpeed (e.g. for a nightly build) and (b) you have to make sure that the custom templates are distributed to every machine that might build the project. 2. Copy these files to a location that's part of the project (where they can be part of the project's source control) and edit them there. In this case you will need to tell the project to use the templates from the custom location: to do this, select the project node in Solution Explorer and edit the LightSpeed Template File setting in the properties window to point to your copy of Base.vm (which will #include everything else it needs). It will be your responsibility to merge in enhancements and bug fixes from the original template files if you need them. We generally recommend the second option. The template files are NVelocity templates -- see the Velocity documentation for syntax, though most of it's pretty self-explanatory. The particular file you'll be interested in editing is Fields.vm, which generates the backing fields for entities, and is therefore also responsible for things like validation attributes. Near the top of this you'll see the following: #foreach ($attribute in $field.Attributes) You'll need to change this to insert your extra property into the attributes, or to replace them altogether. One difficulty here is that TranslateAttribute is monolithic: it takes a representation of an attribute such as a validation, and returns the code for that attribute. So you would need to either operate on the code as a string, or bypass the TranslateAttribute method for your specific cases. The latter is probably easier for specific cases, so you would need to do something like (not tested): #foreach ($attribute in $field.Attributes) This in turn raises the issue of where to get the errorid from. For this you will probably need to depend on a naming convention e.g. entityName + "Errors." + propertyName + "Length": [MyValidationNamespace.ValidateLength($attribute.Minimum, $attribute.Maximum, You may need some trial and error here -- and unfortunately NVelocity error messages tend to be less than descriptive. The API used by the templates is not documented so you may need to do some inference and spelunking but we would be happy to advise on specific issues. This is getting to be a bit of an epic so I'll come back to the namespace issue in a separate reply. |
|
|
Right, on to the namespace issue. First of all, since we've already talked about customising the templates, let's look at the additional customisation required for namespacing. In this case we'll need to edit Entity.vm and just wrap the whole thing in a subnamespace. (We could also do it in Base.vm, around the #parse("Entity.vm") directive.) So at the beginning of Entity.vm we need to add something like this: namespace $entity.Namespace // for illustration only; won't work; see below for real syntax and at the end of Entity.vm we need to add the associated closing brace: } Now, if you try this, you'll get NVelocity error spew (or nothing, depending on NVelocity's mood), because the designer doesn't provide a Namespace property on the entity model. So this brings us to the second problem: how do we attach custom data (such as a namespace) to an entity in the designer and consume that in a template? The answer is something called extension properties. Here's how to set them up: 1. Go into the model explorer (View > Other Windows > LightSpeed Model). 2. Right-click the root (model) node and choose Add New Extension Property Definition. 3. Select the newly added definition and go into the Properties window. 4. Change the Name to EntityNamespace and the Extends to Entity. (You can supply a Category, Description and Display Name if the mood takes you, but they're not required, and the default data type of System.String is correct for this case.) Now select an entity on the design surface. You will find it now has an EntityNamespace property in the Properties window. (If you're using Category view, and didn't specify a particular category, it will be in the Misc category.) You can now enter the sub-namespace you want for this entity. So now we have a way of associating namespaces with entities, how do we get the template to consume it? Here's the syntax you need: namespace $entity.GetExtendedPropertyValue("EntityNamespace") (And of course you'll still need the enclosing braces around the body of Entity.vm.) One thing to watch out for is that this will throw an exception if the EntityNamespace extension property isn't defined. You can get around this by calling HasExtendedProperty or by passing in a default as an optional second argument to GetExtendedPropertyValue. See http://www.mindscape.co.nz/forums/Post.aspx?ThreadID=1956&PostID=5101 for more info about these APIs and the extension properties feature. (By the way, if the error IDs for the validation feature aren't conventionally named, you might be able to use extension properties on the property/field (on the Extension Property Definition, set Extends to Property) to pass info about the error IDs to be associated with a validation. This will depend on the details of your design though and is left as an exercise for the reader *grin*.) Hope this helps -- as I said this is moderately ninja so if you need more info or run into problems then do let us know. |
|
|
Sorry for not getting back to you sooner Ivan, I had to do a few other things. Now that I'm back to this, there's one more feature request/question I have about the generator. We run a rails style migration for our upgrades. Is it possible to get the plugin to append SQL statements it executes when it modifies the database to a file? This way we can make changes in the GUI, then copy the changes to a migration file such as 140_Schema_BillingUpdates.
Thanks, Todd |
|
|
In the Update Database dialog, select the Log SQL checkbox. This will display the executed SQL in a Visual Studio document window from where you can save it or copy it to the end of another file as required. |
|
|
Hi Ivan :) .... |
|
|
The setting will appear in the Properties window only if the project contains a .lsmodel file. (Which yours clearly does.) Also, we did at one point have a bug where it would appear only if the .lsmodel file was in the root of the project (not in a subfolder); this should be fixed in current builds but might affect older builds (or we might have a regression). Also, at the risk of pointing out something I'm sure you've already noted, don't forget you need to click on the project node (.csproj file) in Solution Explorer, not on the LightSpeed model itself. If it consistently refuses to appear, you should be able to edit it directly into the .csproj file as follows: <ProjectExtensions> (If the ProjectExtensions section doesn't already exist, it belongs as a direct child of the <Project> element.) Hope this helps -- please let us know if you still run into problems. |
|
|
Hi again Ivan,
This following is what is generated, when I just let MindscapeLightSpeedTemplatePath point to "C:\Program Files\Mindscape\LightSpeed\Tools\Designer\Templates\C#\Base.vm"
using System;
using Mindscape.LightSpeed;
using Mindscape.LightSpeed.Validation;
using Mindscape.LightSpeed.Linq;
namespace SANSIRNET.Modules.eCommerce.Infrastructure.Entities
{
///
/// Provides a strong-typed unit of work for working with the model.
///
[System.CodeDom.Compiler.GeneratedCode("LightSpeedModelGenerator", "1.0.0.0")]
internal partial class UnitOfWork : Mindscape.LightSpeed.UnitOfWork
{
///
/// Initializes a new instance of the UnitOfWork class.
///
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public UnitOfWork()
{
}
}
}
There is a C# folder and a LightSpeedModel folder, both of which contain a Base.vm file. Is it ok to ignore the LightSpeedModel folder?
|
|
|
Chrome is not working well with the forum. So here goes FF: |
|
|
That looks like it's finding the correct template but there are no entities in the model. Should there be? Don't forget you need to make an edit to the model to force VS to regenerate the C# file. Yes, you should ignore the LightSpeedModel folder. That is used only by the lsgen.exe command line tool, when creating a .lsmodel file from a database. |
|
|
Hi Ivan, thanks for your help. |
|
|
Could you take out the $(ProjectDir) please? We don't expand build step macros. Just specify a path relative to the .csproj file: Entities\LSTemplates\Base.vm Let me know if that still doesn't work (and whether it generates nothing at all, an empty file or a file with partial content like the one you posted earlier). Also we did at one point have a bug where it resolved relative paths from the VS program directory, rather than from the project directory, so if you're on 2.2 RTM it might be worth trying with the current nightly build. |
|
|
Got it to work by doing what you said! :) Thanks a bunch, Ivan. Your support is unprecedented! Btw, I use LS3 beta ;) I believe I have tried it with that "Entities\LSTemplates\Base.vm" before, but I have probably just saved when having the LS model open and not modified anything, which perhaps caused the almost empty file.
Thanks for a great ORM. It is nice :) Now you just need to give us a provider for RIA services and a way to cache linq query results that automatically get updated if any given entity suddenly does fulfill a query or if some new entity instance comes along that fulfills the query by membership testing on cached queries ;) |
|
|
[quote user="ahjohannessen"]Related to this, I have an important question. What does LS use to populate the relational collections, e.g. EntityCollection, on an entity. I hope the generated model, but i suspect it is not as simple.[/quote] Bad news, I'm afraid. Child collections do not go through the LINQ unit of work, but instead perform a raw query on the foreign key using the Find method: effectively unitOfWork.Find<ChildType>(Entity.Attribute(fkName) == this.Id); So I'm afraid entities with IsArchivable set to true will still appear in the child collection, even though you have modified the LINQ model. A possible way around this is to not surface the EntityCollection directly as a public property. For example, you could modify your property definition as follows: public IEnumerable<ChildType> Children { LightSpeed will still end up loading the archivable rows into the private _children field, so this isn't as performance-efficient as it might be, but it does mean that the Children property will return only "live" entities. (You can also do this more efficiently by using a children query rather than the Children collection: this.Query(p => p.Children).Where(c => !c.IsArchivable) will return only the rows you want.) However, some thought would be needed to adapt this trick to allow you to add and remove items via the Children property (or you could duck with issue by generating AddChild and RemoveChild methods). [quote user="ahjohannessen"]Now you just need to give us a provider for RIA services and a way to cache linq query results that automatically get updated if any given entity suddenly does fulfill a query or if some new entity instance comes along that fulfills the query by membership testing on cached queries ;) [/quote] |
|
|
[quote user="ivan"] Bad news, I'm afraid. Child collections do not go through the LINQ unit of work, but instead perform a raw query on the foreign key using the Find method: effectivelyunitOfWork.Find<ChildType>(Entity.Attribute(fkName) == this.Id); So I'm afraid entities with IsArchivable set to true will still appear in the child collection, even though you have modified the LINQ model. public IEnumerable<ChildType> Children { [/quote] I think you have a nice and agile product :) Always nice to read your blogs and learn about your solutions to things. Clever guys ;) |
|