Could we 're-link' a part in a Content Item - CustomerPart/UserPart

Topics: Core, Customizing Orchard, Troubleshooting, Writing modules
Mar 9, 2013 at 11:39 AM
Hello,

Writting in the dark as Codeplex has Iframe pbs....

I follow the skywalker sample to create a Customer part and attach a UserPart to each new CustomerPart Created. I works Ok.
The Customer ContentType contains The CustomerPart and the UserPart.

My problem is adding a CustomerPar to existing Users, I can't find a way.
I tested this code without success (user is an Orchard legacy UserPart retrieved from the authenticated user.)
var contentItem = _orchardServices.ContentManager.New("Customer");
            var customer = contentItem.As<CustomerPart>();
            customer.LastName = user.UserName;
            var userPart = customer.As<UserPart>();
            userPart = user;
            _orchardServices.ContentManager.Create(contentItem);
It should have been too easy...
The customer contentype is created but not containing the UserPart, only the Customer Part ???
Coordinator
Mar 9, 2013 at 7:43 PM
First you need to add the Part to the Content Type in the as in the content definition manager. This can be done within the Admin, Content Types, Users, Add Part. Or by code using IContentDefinitionManager.
Mar 10, 2013 at 7:44 AM
Thanks Sebastien, I understand that you answer to my title.
Because the text is still in the fog.

In fact my question was not totally describing the pb: the concern is already cerated instances of the parts, not the parts themselves, I have used and adapted the sample code from the good Skywalker site, here
http://skywalkersoftwaredevelopment.net/blog/writing-an-orchard-webshop-module-from-scratch-part-8

My pb is that I have USers without Customer par and want to extend theme.
And du to some textsing customers without User Parts (my code on first post did this)
Developer
Mar 10, 2013 at 10:09 AM
Edited Mar 10, 2013 at 10:10 AM
var contentItem = _orchardServices.ContentManager.New("Customer");
            var customer = contentItem.As<CustomerPart>();
            customer.LastName = user.UserName;
            var userPart = customer.As<UserPart>();
            userPart = user;
            _orchardServices.ContentManager.Create(contentItem);
Just being curious: what is the intent of the 4th and 5th line exactly? You're casting a customer to a UserPart and assigning it to a variable called userPart, and on the next line you overwrite that variable with a user instance.

If you want to attach the CustomerPart to the User content type, you could do so using an ActivatingFilter or by using the ContentDefinitionManager.
Mar 11, 2013 at 7:34 PM
Edited Mar 11, 2013 at 11:24 PM
I just tried a variant on the working/existing code
        public CustomerPart CreateCustomer(string email, string password) {
            var customer                = _orchardServices.ContentManager.New("Customer");
            var userPart                = customer.As<UserPart>();
            var customerPart            = customer.As<CustomerPart>();

            userPart.UserName           = email;
            userPart.Email              = email;
            userPart.NormalizedUserName = email.ToLowerInvariant();
            userPart.Record.HashAlgorithm = "SHA1";
            userPart.Record.RegistrationStatus = UserStatus.Approved;
            userPart.Record.EmailStatus = UserStatus.Approved;

            _membershipService.SetPassword(userPart, password);
            _orchardServices.ContentManager.Create(customer);

            return customerPart;
        }
Now that you can read my original question, related to the conversion of existing users before the CustomerPart installation, could you provide a way to extend this 'users only' to 'users+customers'


I must admit that the contentItem is still mysterious for me, but with some help...and I have also read the comple H2G2 from Douglas Adams (being born in a departement identified with number 42, I am optimistic on a solution)
So could we do what I am trying and what is the usual way ?
Developer
Mar 11, 2013 at 9:36 PM
If I understand correctly, you are looking for a way to turn existing "User" content items into "Customer" content items. You probably have a couple of existing User content items but decided that they should be Customer content items instead, correct?

If so, then you could write a method that runs once through all Users, creates a new Customer, then removes the User from which a Customer has been created.

You can regard a ContentItem as being an "instance" of a Content Type, which is its blueprint. Like having a C# class (type) and instances of that class (items).
Mar 11, 2013 at 11:09 PM
Edited Mar 11, 2013 at 11:24 PM
Ok thanks, I understand that it is exactly what I was fearing.
One Part Instance may only belong to one contentType Instance. In other terms, a contentpart occurence may not be shared by different contentypes
This is the actual limitation in the Orchard, isn't it ?

Does migration to a real document model DB could change this ?

Concerning Users, that's quite impracticable because we have no access to password, and could not create news userPart inside the Customer item ???
Coordinator
Mar 12, 2013 at 1:33 AM
No, that doesn't make sense. A content part is attached to a content item, not a content type.
Mar 12, 2013 at 8:01 AM
Here is what I understand.

Content Parts and Content Types are metadata building a kind of metadata map behing Orchard, kind of class descriptions ?
Conceptually the 'frame' of a Content Type is designed by assembling various Content Parts.
So a Content Part, as metadata, may be implied in several Content Types.

The Instance of a Content Type is a Content Item ? Containing an array of Content Parts instances and various methods and parameters ?
Difference here is that an instance of a Content Part is only attached to one Content Item, not sharing admitted between other Content Items relaying on a defferent Content Type definition?
Coordinator
Mar 12, 2013 at 11:26 PM
What we have is a dynamic, runtime-defined type system that is based on composition (as opposed to inheritance).

Content items are instances of content types, and an aggregation of content part instances. It is correct that a given part instance only belongs to one item (in the same way that a property value is attached to an object in classic OOP). But of course parts can be re-used across types. If data needs to be shared by all instances of a part, that's a part setting.

I do not see this at all as a limitation of Orchard and document DBs aren't going to change that.
Mar 13, 2013 at 12:23 AM
Ok thanks.

And in the case were, as in Skywalker sample for ecommerce, we add to Orchard a Customer Type defined with a CustomerPart and an UserPart, all the previously created UserPart occurrence which belong to a UserType content item can't be moved from the 'UserType' content item to a CustomerType content Item.

Is there really a show stopper to have a same Part occurence belonging to several content items ? ContentManager.Get<MyPart>(Id) will always return the part, only pb is in its related contentItem which will not be unique. But its is another story....
Developer
Mar 13, 2013 at 12:43 AM
Edited Mar 13, 2013 at 12:43 AM
To be fair, I did see one showstopper once in Orchard: me, when I started and failed understanding shapes, drivers, parts and types the first time ;)

Sharing a part between content items makes just as much sense to me as when you want to share a property between two objects.
Meaning, this only makes sense if you store a pointer / reference to the shared object.

If you want to share the data of a content part, what you really need is a reference to a content item that stores this shared data.

In your case of transferring User data to Customer data, I think you could retain the passwords if you use IRepository<UserPart> to fetch the record and copy the raw values.
Coordinator
Mar 13, 2013 at 12:44 AM
Yes, the show stopper is that a part doesn't make sense without its content item. They are no more independent of their content item than a property is independent of the object it's on. You're doing it wrong. In OOP, you can have a property that is a pointer to another object. Similarly, in Orchard you can have a part that points to a user.
Coordinator
Mar 13, 2013 at 12:45 AM
There :) we were writing pretty much the same answer at the same time...
Developer
Mar 13, 2013 at 12:56 AM
:)
Mar 13, 2013 at 7:20 AM
Edited Mar 13, 2013 at 7:22 AM
Thanks for all, this, I think it could help new Orchard users like me to make their mind on all these internal choices which behind the 'all dynamic world' are still writing static rules in marble.
Mar 13, 2013 at 7:44 AM
Edited Mar 13, 2013 at 9:13 AM
I would add that for a 'new user' (but not a new dev) Orchard has very nice features which could be from best to worst: all the IOC with autofac, the MVC routing, the contentype/content part design, the shapes and their dynamic nature, the transparent storage managed by NHibernate.
But it also suffers from some 'hidden' limitations' which sometimes make you spending hours searching and trying for a stable/generic solution.
Reading all the comments on the various boards and blogs clearly shows that this last point is difficult to understand for people who are in the project since its early days and have written so many time the same positives explanations and large documentations.
I understand this could be uneasy to admit.
Developer
Mar 13, 2013 at 1:27 PM
Of course there are limitations, I have yet to see a system that has none. If there were no limitations we would all call it a day and enjoy working with the end result, if there is such a thing. :)
Just out of curiosity, what "hidden limitations" are you referring to?

I'd be the first to admit that starting out with Orchard development can be intimidating / appear complex for new devs, even with an MVC background. Most of us have been there, but we are not forgetting it. This is the primary reason why we help out on the forums, write blog posts, record videos and work on documentation. The concepts aren't all that hard once they are explained.
Mar 13, 2013 at 2:45 PM
Edited Mar 14, 2013 at 8:41 AM
Do not misunderstand, I appreciate all your help, the skywalker blog is part of my bible.
It's always easier to be critical, I know but without critics no progress, the idea is to be constructive. But all this is trivial.
Concerning hidden limitations, I know that you will not agree, but the object structure is complicated and its mapping to SQL DB seems not optimum.
This is very complicated by the non commented code option chosen and the dynamic programming.
It is not easy to debug, (object languages were already complicated but with the dynamic keyword its more difficult, I am happy we get rid of Clay....)

Look recently I had a problem with a mediapicker field (the ProductImage from Nwazet Commerce), it appears that the product part has no fields when it is time to display it in Shopping cart summary (no an urgent pb because it's a summary and pictures take lot of place), and also because they display normally in the product detail page.
Bertrand told me it's perfectly working on its side.
My code is from a variant of Nwazet bringing some features as product recommendations, etc. Parts have been added to the Product Content Type using legagcy methods.

This morning I was debuging another pb in shopping cart and I take the opportunity to try understanding why my fields were not present in my productparts.
I just discovered that the product contentItem contains 13 parts, and amongst them there is the productPart but also an Orchard.ContentManagement.ContentPart.
Was looking as some internal plumbing.
But inspecting it, I discovered my imagePicker field is here ???? I have never read something about this ? why is it created when the product item is loaded ? Why the productPart field is inside this part????
Is it the ProductPart which is a proxy object, what is this new Part that has never been added to the Product Content Type.....
This is an exemple of what I would put in the hidden limitations: complexity.

Another would be the problem I reportd here: for me its totally illogical to have some Userparts being inside a Customer Type, and some other inside an User Type. And represent the same kind of logical entity.
They should be on same level of management, or it should exist some easy way to better adapt. When I run some code based on your ecommerce blogs, with normal users I get an exception because they are authenticated but have no associated Customer Part. So either I create a special batch to upgrade them (not cool) either I created some quick and dirty passthrough breaking a clear code.


Starting with Orchard is not intimidating, it is time consumming,.
Coordinator
Mar 14, 2013 at 1:30 AM
I have no problem admitting limitations when they are real. I do it every day. But all I see here is a lack of comprehension of the platform. What seems illogical to you actually is perfectly logical and thought through. Complexity is not a limitation in itself. It comes as the price of this form of flexibility. I think you should let us explain to you how to implement your specific scenarios, instead of what I think I see here, which is that you have made up your mind about how you think it should be implemented and demand that Orchard bends to your way of seeing things.
Mar 14, 2013 at 8:37 AM
Edited Mar 14, 2013 at 8:40 AM
Let's go.
And thanks for your time, I appreciate.
So have you some ideas on the two 'non problems' I just related ?
Here is what I get inspecting my product contentitem (hope it will display ok, using skydrive ??!!)
Could you explain what we see here ?

![http://sdrv.ms/X9fM82]
Developer
Mar 14, 2013 at 10:22 AM
Could you first explain what in your mind seems to be the problem with that picture?

All I see is a content item, its parts and its fields. I also see that some parts are "strongly typed", like "TitlePart" and "TagsPart", and others aren't. A part is welded on to a content item in a "strongly typed" way when there is a driver associated with it.
For example, if you create a ProductPart, but you don't create a driver for it, it will be instantiated as a ContentPart instance instead of the derived ProductPart instance.
Mar 14, 2013 at 10:35 AM
Edited Mar 14, 2013 at 10:47 AM
my pb ( 'in my mind as you say' :) !!! ) was reported and detailled here

http://orchard.codeplex.com/discussions/434803

the problem, as I said previously, is that the 'Poduct Image' field is in this 'welded ?' content item and not in the productpart ?? does this mean that there is a pb in my product driver ?

Why two parts for product ? This clearly explains the pb in shoppingcart.summary where there is no picture for the product.

I pusblished my code here this morning in case you want to check the full code

https://bitbucket.org/csurieux/datwendo.commerce

Would my pb caused by the fact that I replaced original Nwazet product driver by mine ?
[OrchardSuppressDependency("Nwazet.Commerce.Drivers.ProductPartDriver")]
public class Product2PartDriver : ContentPartDriver<ProductPart> {
Developer
Mar 14, 2013 at 11:12 AM
Edited Mar 14, 2013 at 11:13 AM
I don't see any Product Image field in your screenshot, so I will assume that it's the MediaPickerField underneath _parts[2]. That field is not directly attached / welded on to the content item, but to a content part (_pats[2]). Why this field is there instead of underneath the ProductPart (_parts[7]) is impossible for me to tell, since, after all, you are the one who attached fields to parts or wrote code that does that for you, right?

Not sure what you mean with: "Why two parts for product"?
I actually see 13 parts attached to the Product content item in your screenshot. Why they are there is because you or your code is doing that.

About whether or not your problem is caused by replacing Nwazet's driver with your driver is hard to tell without seeing and debugging your code, but unfortunately that's outside the scope of what I can do right now.
Mar 14, 2013 at 11:18 AM
Edited Mar 14, 2013 at 11:58 AM
Ok, on my side I suspect some bug in Orchard.
As I said this is not a show stopper for my module and I think I will find the issue later in time.
... Orchard is time consumming.
Have a good day.
Coordinator
Mar 14, 2013 at 5:49 PM
No, it's not a bug in Orchard. I've explained in the other thread.