Can I treat CSLA BusinessBase class as EF4 Code First classes

Can I treat CSLA BusinessBase class as EF4 Code First classes

Old forum URL: forums.lhotka.net/forums/t/9586.aspx


tikluganguly posted on Wednesday, September 29, 2010

Hi,

     Based on my understanding it is quite possible to treat the csla buisnessbase (or readonlybusinessbase) classes as ef4 code first classes.

          Please do let me know if I am correct.

 

Regards

Tiklu

RockfordLhotka replied on Wednesday, September 29, 2010

If you are able to get this to work, please share your findings.

I suspect it might work in some simple cases, but probably won't work if the object graph is anything but trivial, and I can't imagine it would work if you use managed backing fields (which are basically required to support Silverlight or WP7).

Remember that any code external to your object (such as an ORM) can't get/set property values directly, because that'll trigger business rules. The best case is that performance would be poor, but more likely the object will refuse to get/set some values due to authorization rules.

So any external code really needs to set field values, not property values. Technologies like BinaryFormatter and NetDataContractSerializer do this, which is why they work well for CSLA. Perhaps EF can do this too?

But if you use managed backing fields, then you have no private fields, in which case any external code actually needs to invoke ReadProperty/LoadProperty - and that implies that the external technology (like EF) has hooks where you can plug in your own code for any get/set operations.

At one point the EF team did plan to have such hooks in EF 4, and I'd discussed with them how this might work. I don't think that feature made it into the final release of EF though. But if I'm wrong, I'd love to hear about it - because it would be really cool :)

tikluganguly replied on Thursday, October 07, 2010

Hi Rocky,

          First of all sorry for replying you back after so many days. Please do have a look at my code which I have attached to this post. As you can see it is basically a very simple object getting saved to the db. To run the code you would be needing ef4 futures ctp 4 and obviously CSLA 4. If you see the dbcontext class you will see that I have specifically mapped only the properties which I need to put in the db, which is actually skipping all the other businessbase classes like isbusy, isdirty etc. 

           Also if you see the code is written in a very simple way. If required we can even improve the performance of saving/loading data with the help of doing some server side caching of the dbcontext. Also I do believe by following this technique we can also save very complex data's too. I am still doing some research of my own to extend this demo to work on some more complex data graph.

        Please do let me know your feedbacks on it

Regards

Tiklu

 

RockfordLhotka replied on Thursday, October 07, 2010

I'll try to look at this when I get a chance, but it won't be any time soon.

The one thing to remember is that you can't use property getters and setters directly without running authorization and business rules. To avoid that you need to call ReadProperty and LoadProperty, which aren't normally public. However, if you can put the EF related code into an ObjectFactory subclass you can get at those methods.

tikluganguly replied on Thursday, October 07, 2010

Got It, I will go in that direction. Also you are correct if we directly use setproperty and getproperty, which is what i have used in my code it would prevent an user from loading a particular value from db if he does not have a permission, and which in turn may just crash the whole code. 

            Lets see if i can come up with something with ObjectFactory. I will surely post you my findings on that

tikluganguly replied on Friday, October 08, 2010

Hi Rocky,

            As you said the trick was to somehow skip the setpropery and getpropery methods, and this is how I did it.

 

First I created one EFBusinessBase which inherits from BusinessBase and overriden the setproperty like this

 

 

public new void SetProperty<P>(PropertyInfo<P> propertyInfo, P newValue)

        {

            if (isReady)

            {

                base.SetProperty<P>(propertyInfo, newValue);

            }

            else

            {

                base.LoadProperty<P>(propertyInfo, newValue);

            }

        }

 

 

Similarly for get property it is

 

 

public new P GetProperty<P>(PropertyInfo<P> propertyInfo)

        {

            if (isReady)

            {

                return base.GetProperty<P>(propertyInfo);

            }

            else

            {

                return base.ReadProperty<P>(propertyInfo);

            }

        }

 

 

I also have another method in the business base called MarkReady as

 

 

void IEFBusinessBase.MarkReady()

        {            

            this.isReady = true;

        }

 

Now I did also created a new class called CSLADBContext where in ObjectMaterialized event I am doing the following

 

void ObjectContext_ObjectMaterialized(object sender, System.Data.Objects.ObjectMaterializedEventArgs e)

        {

            var entity = e.Entity as IEFBusinessBase;

            if (entity != null)

            {

                entity.MarkReady();

            }

        }

 

So this event actually gets fired once all the values for an entity is set and at that time i am also setting the the isready flag variable to true. and thus enabling the business validations and authorization rules only after the object is fully materialized. 

Also inside the dataportal_fetch I am just directly adding the objects to the list like this

protected void DataPortal_Fetch()

        {

            PersonDbContext ctx = new PersonDbContext();

            ctx.Database.CreateIfNotExists();

            var items = from p in ctx.Persons select p;

            this.RaiseListChangedEvents = false;

            foreach (var itm in items)

            {

                Add(itm);

            }

 

            this.RaiseListChangedEvents = true;

        }

As you can see i am directly adding the items to the list. The only problem that I am getting with this is the person objects are not properly responding to the property change (i.e not marking an object as dirty)...I think I do have to add some code for that in the MarkReady method. If you can give me some hint here, then that would be nice...

  Again I have added the code with this reply...in case you find this post interesting then please do have a look at that

 

Regards

Tiklu

tikluganguly replied on Friday, October 08, 2010

Hi Rocky,

             The last problem that I was getting because I was not serializing isReady using the mobile formtter. Now I did that and it is working fine now..

As of now the MarkReady has been changed like this

 

void IEFBusinessBase.MarkReady()

        {

            this.MarkAsChild();

            this.MarkOld();            

            this._isReady = true;

        }

 

and I have added the _isReady variable to mobileformatter as

 

protected override void OnSetState(Csla.Serialization.Mobile.SerializationInfo info, Csla.Core.StateMode mode)

        {

            base.OnSetState(info, mode);

            _isReady = info.GetValue<bool>("Mazik.EFCSLA._isReady");

        }

 

        protected override void OnGetState(Csla.Serialization.Mobile.SerializationInfo info, Csla.Core.StateMode mode)

        {

            base.OnGetState(info, mode);

            info.AddValue("Mazik.EFCSLA._isReady", this._isReady);

        }

Now it is working fine

Regards

Tiklu

 

RockfordLhotka replied on Friday, October 08, 2010

That's great!

Copyright (c) Marimer LLC