Basic CRUD without ContentParts

Topics: Troubleshooting
May 19, 2011 at 5:22 AM

Hi,

I would like to be able to do basic CRUD using the current IRespository<TRecord> implementation. What I'm seeing is a strange error that says

attempted to assign id from null one-to-one property: ContentItemRecord

I understand a bit where this comes from, but is there any way I can get around it? Or can I somehow save that Item, maybe by saving a ContentItemRecord.. I'll try it and tell you how it goes.

Other thoughts in the meanwhile ?

 

 

 

May 19, 2011 at 7:32 AM

What happened is that I had manually inserted some values in my table using the SchemaBuilder.

The problem appeared because whenever a new MyRecord instance was created it added a new entry to ContentItemRecord which had an Id lower than the id in MyRecord table. 

This means that migrating existing data just got a lot harder. Any migration script we write in order to port existing data needs to account for the fact that the relation between contentItemRecord id and your own Record needs to be in balance.

Someone asked a question, at some point, of whether or not he could reuse an existing Product table. The way to do this is, as far as I can see, is to have a product record in Orchard that acts as a 1 to 1 between what Orchard represents and what your table with data represents, or ignore anything Orchard offers and just reuse NHibernates ISession instance.

 

What I ended with is to parse a string of some delimitor-separated values and have NHibernates ISessionLocator injected to the migration class in order to push the values to the DB. 

I'm open for other suggestions on how to tackle this. Also, I'd like to see a practice in place for migrating data to Orchard.

*Rant* You never now when you'll want to drop Sharepoint-Pain-In-The-&$$, or even an other CMS's data, in favor of Orchard and will need some nice ways of integrating that data.

May 19, 2011 at 9:53 AM

Well it would probably help if you posted your Migrations code ;)

The thing is you don't *have* to make a table be a ContentPartRecord. You can just build your own tables and have an IRepository<MyRecord> to perform CRUD. I've done this and it works fine so I don't know where you've gone wrong here ... ?

May 19, 2011 at 10:10 AM
Edited May 19, 2011 at 11:12 AM

I went wrong in a couple of points.

First I didn't initialise MyRecord.ContentItemRecord.

I then tried to make the Id of MyRecord be PrimaryKey 

Third I was inserting by hand INSERT INTO MODULE_MYRECORD data.

Fourth I don't now how to insert the data that I need to migrate without relying on NHibernate, but instantiating a NHibernate Session in the Migration class, even if I set it to Lazy<ISessionLocator> automatically creates those tables in SqlCE ( that is how I configured it in the tests, but I think on the website is the same ).

I see that NHibernate does INSERT into Orchard_ContentItemRecord, then it does a select @@Identity and finally it does insert MODULE_MyRecord with the id set to the previously selected @@Identity.

I understand your point, but my envisioned workflow was to migrate non-contentrecord data to contentrecord data.

It is mostly experimentation at this point, I wanted to see how far i could go.

EDIT 1

AbstractDataServicesProvider.cs would indicate that I can define a RecordBlueprint in order to map other types ,that do not extend ContentPartRecord.

I see a CompositionStrategy.cs that searches for ContentPartRecords. So my thoughts are that I need to create an Autofac.Module and register a RecordBlueprint type. Is this what you did? (I'll be back after I check this out ).

EDIT 2

CompositionStrategy.cs seems to be responsible for selecting Records using the IsRecord method below

  private static bool IsRecord(Type type) {
            return ((type.Namespace ?? "").EndsWith(".Models") || (type.Namespace ?? "").EndsWith(".Records")) &&
                   type.GetProperty("Id") != null &&
                   (type.GetProperty("Id").GetAccessors() ?? Enumerable.Empty<MethodInfo>()).All(x => x.IsVirtual) &&
                   !type.IsSealed &&
                   !type.IsAbstract &&
                   (!typeof(IContent).IsAssignableFrom(type) || typeof(ContentPartRecord).IsAssignableFrom(type));
        }
So it should be that if I have a type under Models or Records, that has an Id property with a get accesor marked virtual, its not sealed and is not abstract, it does not extend IContent than it is considered a valid Record.

If you say you've created entities without relying on ContentPartRecord I would very much like to know how you've plugged into the FluentNHibernate configuration to achieve this.

May 19, 2011 at 11:12 AM

Ok the problem here is that if you want to populate a content part record, you have to go thru the content manager, using the New and Create methods to build an item then save it. You can't just insert records into your table because there will be no content item for it to join to!