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
|
I have a really simple entity mapped to a table: [Table("host", IdColumnName="id", Schema="tt")] }
When I retrieve an Entity, the Name filed gets mapped but the Id field does not get mapped. Calling GetId() shows the correct value. What am I doing wrong? This is the code: var context = new LightSpeedContext<DashboardModelUnitOfWork>("TracetasticDev");
|
|
|
You are explicitly declaring an _id field, so I am guessing you also have an Id property which wraps the _id field. This Id property is shadowing LightSpeed's Id property: GetId() is getting the LightSpeed Entity ID, but hosts[0].Id is getting the shadowing property. You never need to declare the Id yourself in LightSpeed: it is defined on the base class for you. If the designer has inferred an Id property from the database schema, this probably means Id is not a primary key in your database (the designer infers the identity column based on PK, not name, though if it couldn't find a PK it should have emitted a warning). Your schema does appear to be defining id as a PK though -- we will have to investigate this. Can you let us know which database you are using please? Anyway, just delete the inferred Id property and you should be good. (By the way, if this is designer-generated code, it should be giving a compiler
warning because the designer does not emit the "new" modified onto
generated properties. So C# should be kicking about shadowing without
"new.") |
|
|
This is SS2005/SS2008. I put the Id field on the entity myself. Basically I need to get the Id into the WCF generated DTO. So, perhaps this is a bug in the WCF templates then. I assume that the templates should be generating the Id field on the DTO and they are not. |
|
|
It's a (somewhat controversial) design decision in the WCF templates. We don't put the Id into DTOs because of concerns over methods that result in an insert. It would be misleading to expose a contract that allowed the client to send a message that effectively said "add this data and give it ID 3045," because LightSpeed would discard the requested ID and assign its own ID. So when the client said, "okay, that item with ID 3045, I want it back please," they would get nothing, or a completely different set of data. There are extensibility hooks in the generated DTO code (which I think were added post-2.2, so you will probably need to grab a nightly build to use them) which allow you to copy the Id into the DTO (we added a common base class so you need to do this only once). Alternatively you can send the Id as a separate field in messages which have select, update or delete semantics (indeed a message with delete semantics will probably want to send only the Id anyway). We welcome feedback on this -- as I said the design decision was a bit controversial but I hope this at least explains what the reasoning was! |
|
|
Hi Scott, Hope you don't mind me reproducing your email here, but I'm interested in getting broader opinion on this. You wrote: This is definitely controversial and I think neutering the read scenario is not incredibly desireable.
Also, the update scenario needs to be addressed. I mentioned this in a previous approach. I think you need to support a simple change tracking facility and/or support for some kind of surrogate key. So, the client can provide a guid and then lookup the entity via that. This is less infrastucture and more standardization of how the datacontracts should work with LS. One of our high-priority items for LightSpeed 3 is much deeper support for distributed applications. We have been thinking about a change-tracking mechanism for services for some time now and that's something I'm expecting to happen in v3. That should solve the read/update/delete vs. insert issue. We will have a look at how we can improve the DTOs in 2.2 but I think change tracking and surrogate keys are more of a change that we will want to make in a minor revision (and of course compatibility is a consideration). You can of course implement your own surrogate key system via a GUID field on a base class (using concrete table inheritance or an external base class), and define your service operations in terms of that surrogate key. (CTI will work better from the designer point of view because we can then include the field in database sync and DTOs, which we can't do with external base classes, but does add a bit of clutter to the diagram.) Because you can do this through a base class it shouldn't be too painful to implement. Thanks again for the feedback -- as I said there are limitations to what we can do in 2.x but this is really useful for us thinking about 3.0. |
|
|
[quote user="ivan"] There are extensibility hooks in the generated DTO code (which I think were added post-2.2, so you will probably need to grab a nightly build to use them) which allow you to copy the Id into the DTO (we added a common base class so you need to do this only once). Alternatively you can send the Id as a separate field in messages which have select, update or delete semantics (indeed a message with delete semantics will probably want to send only the Id anyway). [/quote] Hi, I am testing Lightspeed with our new application prototype. I really like LS and so far it looks like it will be our choice for ORM. However, doing the prototype, preparing DAL and WCF interfaces, I stumbled upon the issue mentioned in this thread (how to update a record after it has returned as DTO, and hence ID has been lost). Now I downloaded the latest night build, but I fail to realize how to use the feature mentioned above (copy ID into DTO with a common base class). Is there a way to see release features (with small examples) of nightly build changes? |
|
|
Hi Marko, Sorry for the delay in replying. What you would need to do is create partial classes for Contracts.Data.XxxDtoBase and Contracts.Data.XxxDtoExtensions (where Xxx is your model name). In the DtoBase partial class, add an Id property with the DataMemberAttribute. In the extensions partial class, implement the static partial method CopyXxxDtoBase(Entity entity, XxxDtoBase dto). In this method, copy the entity's Id to the DtoBase.Id property you have just defined. The Id will now be copied when you call an entity's generated AsDto method. Note that this does not work in the other direction, i.e. it is not possible to copy the Id from the DTO to an entity. Instead, in an update operation you would use the Id of the incoming DTO to select an entity, then copy the non-Id data from the DTO into the entity using the CopyTo method. Let us know if you need any more info. |
|
|
Hi ivan, Thank you for your answer. Actually in the meantime, I did what you propose, but I was still waiting for your answer to see is there a way to avoid casting Id column (because Entity doesn't have a typed Id property, Entity<Pk> has it). In code:
I.e. I am not sure that it is even possible, because of the design - Dto objects and Entity objects are actually independent. If there is a possibility, please let me know. Thank you again for your support. |
|
|
Yeah, because the Copy methods are implemented as extension methods using a naming convention, rather than as virtual methods on the DTO or Entity classes (the main reason for this being that the core library is currently designed to be usable under .NET 2.0), I don't think an elegant solution is going to be possible. You could probably implement something only moderately ugly using reflection, relying on the convention that the DTO type name will always be the entity name followed by "Dto", but offhand I can't think of anything better than that. Sorry. |
|