Hi,

We have a strange issue. For some reason the Construct of our Contact Class and the initialization of its public properties never get called.

When this class is loaded like this

public static new Person Load(int id)
        {
            var qPerson = from entity in Query.All<Person>()
                                  where entity.Z_Id == id
                                  select entity;

            Person person = qPerson.FirstOrDefault();

            if (person == null)
            {
                throw new EntityNotFoundException("Person", id);
            }

            return person;
        }

The constructors never get called. I must add to that, that the object is already read before (still no constructor and initializing) and probably in the cache.

Here's the (start of) the Contact class from which the Person derives.

public partial class Contact : AbstractIntersectingHistory, IDisposable, IComparable
    {
        public readonly ObservableProperty<string> FullAddressP = new ObservableProperty<string>(null, true);
        public readonly ObservableProperty<string> FullCommunicationP = new ObservableProperty<string>(null, true);

        /// <summary>
        /// The Address that has 'IsPostal' checked or 'null' if none
        /// </summary>
        public readonly ObservableProperty<Address> PostalAddressP = new ObservableProperty<Address>(null, true);

        /// <summary>
        /// The Communication that has 'IsMainCommunication' checked or 'null' if none
        /// </summary>
        public readonly ObservableProperty<Communication> MainCommunicationP = new ObservableProperty<Communication>(null, true);

The initializers of 'FullAddressP', 'FullCommunicationP', 'PostalAddressP' and 'MainCommunicationP' get never called, which is weird. Our code now suddenly fails because these properties remain 'null'. As you can see the class is a 'partial' one. The other part is generated using T4.

Here are the generated constructors.

public Contact()
            : base()
        {
            InitializeMembers(null);
        }

        public Contact(ContactCreateArguments createArguments)
            : base() 
        {
            InitializeMembers(createArguments);
        }

        private void InitializeMembers(ContactCreateArguments createArgumentsIn)
        {// START method InitMembers
            m_Creating++;
            try
            {// START try InitMembers

                // TODO: Check if DataObjects passes the Id as PropertyChanged or not. In case it does, this statement can be removed
                IdP.Value = Z_Id;

                // Dates need to be filled from the model properties once before the attachment of the events           
                if (createArgumentsIn != null)
                {
                    ContactCreateArguments createArguments = (ContactCreateArguments)createArgumentsIn;
                    createArguments.Fill(this);
                }

                if (PersistenceState == Xtensive.Storage.PersistenceState.New)
                {
                    Stamp(EntityStamp.Creation);
                    OnInitializing(EntityInitializationMode.Created);
                }
                else
                {
                    OnInitializing(EntityInitializationMode.Loaded);
                }

                OnAttachChangedEvents();

                // Secure the VersionInfo so we can test if the Entity has changes or not
                m_VersionInfo = VersionInfo;

            }// END try InitMembers
            catch
            {// START catch InitMembers
                throw;
            }// END catch InitMembers
            finally
            {// START finally InitMembers
                m_Creating--;
            }// END finally InitMembers

        }// END method InitMembers

The constructors are also never called. Now we know DataObjects injects code into the classes using PostSharp. We can't however see what code that is so there's no way to debug what is happening. Please enlighten us.

Regards Paul Sinnema Diartis AG


Updated at 02.07.2010 7:39:19

Hi Alex,

I'm almost getting used to your quick responses, really gives us a lot of confidence, thanks.

I can't find your option 'Break on all exceptions'. I've interpreted that as setting all checks in the Exceptions Dialog. We always debug with all exceptions checked. No exception is throw other than a BindingFailure detected in the XMLSerializer ("Could not load file or assembly 'Xtensive.Storage.Model.XmlSerializers'"). The program goes on normally after this exception. Guess there's nothing wrong with this.

We looked at the code a bit. In the DelegateHelper Class the constructor is searched for and explicitly called by code. Can you confirm that during load the constructor isn't called, which could be obvious, because you don't want any initialization for objects that already have data inside. The effect would be that all PropertyChanges would be fired on construction, and that's not what we want, isn't it?

Should we move our initialization code to the OnInitialize() method? This one is called every time a load of an object has finished.

Regards Paul Sinnema & Andres Rohr Diartis AG


Updated at 03.07.2010 5:56:45

Alex,

Sorry, by some reason I thought you're speaking about static constructors, but it's about regular one.

Hah, only provers that your human after all. Welcome to the club. 8)

Yes, DO doesn't call your constructors when materializing the objects by its own. It calls special protected constructor created by our PostSharp aspects - you can see this on stack trace & by Reflector. We suspected as much. The former ORM we used (DevForce by IdeaBlade) had different initialization code (not very clear to us at all time). We did not have the source code of that product so were pretty much in the dark. With DO's open structure we're now able to see how the construct is made (very complex, but we do get the big picture). That's a huge advantage over DevForce's closed source approach.

Regards Paul Sinnema Diartis AG

This thread was imported from our support forum. The original discussion may contain more detailed answer.

asked Jul 01 '10 at 14:47

Paul%20Sinnema's gravatar image

Paul Sinnema
261888896


One Answer:

You can use Reflector (freeware) to study the code injected by PostSharp.

As far as I can judge, DO4 can't affect on invocation of type initializers. The code leading to their invocation is injected during JIT process, i.e. we simply can't affect on this behavior.

More likely, there is something like this:

  • An exception is thrown in the beginning of your type initializer
  • The code leading to invocation of type initializer catches it, but doesn't throw anything.

Try to debug the application with "break on any exception" option to find out the actual casue.


Sorry, by some reason I thought you're speaking about static constructors, but it's about regular one.

Yes, DO doesn't call your constructors when materializing the objects by its own. It calls special protected constructor created by our PostSharp aspects - you can see this on stack trace & by Reflector.

So if you need to to perform some initialization, you must override OnInitialize method - it is called in any case.


Yes, in our case dealing with constructors is really pretty complex, because we must ensure some code is executed before and after your own constructors. And this is tricky, because every constructor must have base .ctor call before the first instruction using this inside its body (otherwise the code won't be verifiable). But PostSharp currently can't inject a code right after base .ctor call - i.e. there is no support for this.

Hah, only provers that your human after all. Welcome to the club.

I just published one more unpleasant proof of this: viewtopic.php?f=29&t=5994

answered Jul 01 '10 at 22:53

Alex%20Yakunin's gravatar image

Alex Yakunin
29714412

Analyzing a bit further:

We see that during 'new' the Constructors are called. Only when an object is fetched using a LINQ Query, the Constructors are not fired. The OnInitialize() is fired on both occassions

(Jul 01 '10 at 22:53) Paul Sinnema Paul%20Sinnema's gravatar image
Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

powered by OSQA