Correct use of SmartDate in CSLA 4.2?

Correct use of SmartDate in CSLA 4.2?

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


gajit posted on Monday, February 27, 2012

I can;t find anything on the SmartDate type in the new eBooks?

What's the correct implementation in 4.2?

In 2.1, I  declared the properties as such:

Private mEFFECTIVEDATE as New SmartDate(False)

    Public Property EFFECTIVEDATE() As String
        Get
            CanReadProperty(True)
            Return mEFFECTIVEDATE.Text
        End Get
        Set(ByVal Value As String)
            CanWriteProperty(True)
            If mEFFECTIVEDATE <> Value Then
                mEFFECTIVEDATE.Text = Value
                ValidationRules.CheckRules("EFFECTIVEDATE")
                PropertyHasChanged()
            End If
        End Set
    End Property

Fetching the value I did as:

                mEFFECTIVEDATE = .GetSmartDate("EFFECTIVEDATE", mEFFECTIVEDATE.EmptyIsMin)

And passing as a datetime parameter to SQL I did:

               cm.Parameters.AddWithValue("@pdt_EffectiveDate", mEFFECTIVEDATE.DBValue)

Basically, In 4.2, I can't see how the emptyIsMin is handled in this version. When I read in a date field - which is NULL, update another field on the BO and save, the date field value becomes 1900-01-01 - that's not the required right...

Any ideas?

Thanks,

Graham 

 

JonnyBee replied on Monday, February 27, 2012

Use the snippets supplied in the Support folder to define properties.

There you will find the "DefineACslaSmartDateProperty" snippet - shortcut "cslapropdt" and more.

For an overview of snippets and templates look at the CSLA CheatSheet available in the FAQ: http://www.lhotka.net/files/csla40/CSLA4CheatSheet.pdf

EmptyIsMin is typically set on the PropertyInfo (RegisterProperty) when supplying a default value for the backing field:

Public Shared ReadOnly StartDateProperty As PropertyInfo(Of SmartDate) = RegisterProperty(Of SmartDate)(Function(c) c.StartDate, Nothing, New SmartDate(EmptyValue.MinDate))

gajit

Basically, In 4.2, I can't see how the emptyIsMin is handled in this version. When I read in a date field - which is NULL, update another field on the BO and save, the date field value becomes 1900-01-01 - that's not the required right...


That is the proper and expected behavior by SmartDate. It will however have .IsEmpty = True and DBValue = DBNull but the internal Date and Text will have a value (either min or max),

gajit replied on Tuesday, February 28, 2012

Yes, I have that in my declaration.

But there is no code for the passing of the value as a parameter in the Dal.

In CSLA 2.x, we passed mMYDATE.DBVALUE, which for a blank smartdate value (the string property), would be NULL.

In CSLA 4, we don't use the private mMydate property, we pas the public MYDATE property.

I can't do a .AddWithValue("@Mydate", MYDATE.DBVALUE)

??

gajit replied on Tuesday, February 28, 2012

I see Rocky showed a solution here;

http://forums.lhotka.net/forums/p/10971/51044.aspx

BUT, is ReadProperty not a method from one of the base models such as BusinessBase?

Dim temp = ReadProperty(ScheduledDateProperty)
cmd.Parameters.AddWithValue("@ScheduledDate", temp.DBValue)

My data access code is in a separate Dal class, NOT in the class bo class and therefore ReadProperty cannot be accessed as a method????!!

How is this implemented?

Graham

JonnyBee replied on Tuesday, February 28, 2012

Look at the Csla.Server.ObjectFactory class and make your data accsess class inherit from this or create a ObjectAccessor class.

gajit replied on Tuesday, February 28, 2012

I can't???

My CodeDal class IMPLEMENTS ICodeDal. How can I inherit from Objectfactory?

Honestly.... it's like pulling teeth this version of the framework.... 2.x didn't require one to understand the inner workings of the framework, now the expectation is that the framework user has to implement a helper type as there if no clear guide on how to do it????

This is my biggest criticism of the current version - that the features are NOT fully documented. The eBook recommedndation is NOT to rollup your data access code into your business object a-la csla 2.x, instead suggesting use of one of the dal models, yet there is no supporting documentation to demonstrate how we implement surviving types like SmartDate.

This is a fundamental requirement for many CSLA 2 users, and I'm flabberghasted that it isn't covered concisely.

CSLA2 helped me develop applications, quickly and cleanly. So far, my progress has been stifled with vague references to 'this or that' and frankly I'm developing at a snail's pace.

Graham

JonnyBee replied on Tuesday, February 28, 2012

Implements and inherits is 2 different aspects. Your CodeDal can both inherit from one class and implement one or multiple interfaces.

Yes, there is more ways of coding the data access in Csla 3.x and Csla 4.

This is described in the Using CSLA4 Data Access ebook: chapter 4, 5 and 6:

Quote:

When the DAL is external, the data access invocation code is responsible for invoking the DAL to
get, save, or delete data. This invocation code might be in your DataPortal_XYZ methods, or it
might be in your factory object methods. Either way, the DAL must expose some formal interface
that can be invoked.

......

It is also the case that some code must interact with the private state and metastate of the
business object to get and set the object’s properties and metastate. As I’ve already discussed, this
can be done in a way that preserves encapsulation by using the DataPortal_XYZ methods, or it can
be done by breaking encapsulation with factory objects and the ObjectFactory base class.

I’ll cover all these concepts, starting with options for the DAL interface.

OR you could just add an extra property in your BO for use in the data access:

    [Browsable(false)]
    [Display(AutoGenerateField = false)]
    public SmartDate AssignedSmartDate
    {
      get { return GetProperty(AssignedProperty); }
      set { SetProperty(AssignedProperty, value); }
    }

 

gajit replied on Tuesday, February 28, 2012

Without sounding blunt Jonny, how the heck does that help?

I've read the quoted passages a number of times, and frankly the excerpts do NOT demonstrate how to access the private state or metastate values in the business object.

I am using the datareader model of the Encapsulated Invoke. NOWHERE does it provide even a hint of a clue on how to access say, the private business value "MyDateProperty" from the Dal. I can only reference "MyDate"

If there are no examples in the book, and no-one is willing to show me a real-life code example of how I would implement it, then once again I've created another post that from my perspective remains "Unanswered".

Extremely frustrated.

 

gajit replied on Tuesday, February 28, 2012

Would I not want to make the "AssignedSmartDate" private?

 

gajit replied on Tuesday, February 28, 2012

That usage of AssignedSmartDate also causes my business object to become 'Dirty' after fetch.

 

 

 

JonnyBee replied on Tuesday, February 28, 2012

I'd still prefer to use ObjectFactory and BypassPropertyChecks --> which makes properties and SetProperty behave as LoadProperty. 

gajit replied on Tuesday, February 28, 2012

And i still have no clue.

Using a separate property to handle the data access isn't working. The BO is dirty when it loads - and yes, I'm using LoadProperty. I as Loadproperty by definition should ignore checks, then I shouldn't have to  

I have no idea how you implement ObjectFactory in the model that I have outlined in this post, so unless someone is kind enough to post a working solution to my problem, then I'll consider it yet another facet of CSLA4 that in my opinion leaves the developer in the dark. If I have to dig for every single change that has happened between version 2 and 4 it makes zero sense for me to adopt this framework, considering the amount of time undertaken.

I appreciate your efforts to educate me, but I have little time to dig deep into the "how it works" and was hoping for a working CSLA4 code snippet in response to my original CSLA2 working code snippet.

Graham

 

RockfordLhotka replied on Tuesday, February 28, 2012

This surely isn't hard enough to be worthy of your anger, frustration, and corresponding outbursts (which I find less and less motivational - how much did you pay for my framework? It was free? Really? And once you've learned to build CSLA 4 style classes they run on every known .NET related platform? Wow that's a good value!!)

What am I missing from the following example? It has a SmartDate property, it uses an ObjectFactory, and the resulting object isn't dirty:

  class Program
  {
    static void Main(string[] args)
    {
      var obj = DataPortal.Fetch<Test>(123);
      Console.WriteLine(obj.Date);
      Console.WriteLine(obj.IsDirty);
      Console.ReadLine();
    }

  }

  [Serializable]
  [Csla.Server.ObjectFactory(typeof(TestFactory))]
  public class Test : BusinessBase<Test>
  {
    public static readonly PropertyInfo<SmartDate> DateProperty = RegisterProperty<SmartDate>(c => c.Date);
    public string Date
    {
      get { return GetPropertyConvert<SmartDate, string>(DateProperty); }
      set { SetPropertyConvert<SmartDate, string>(DateProperty, value); }
    }
  }

  public class TestFactory : Csla.Server.ObjectFactory
  {
    public Test Fetch(int id)
    {
      var result = new Test();
      using (BypassPropertyChecks(result))
      {
        LoadProperty(result, Test.DateProperty, new SmartDate("1/1/10"));
      }
      MarkOld(result);
      return result;
    }
  }

gajit replied on Tuesday, February 28, 2012

My anger, frustration and "outbursts" are a culmination of issue after issue with implementing this framework and not finding sufficient coverage in the books.

I appreciate the investment is small, but you ghave to recognize that there is SOME expectation that the framework does what it has ALWAYS done - and if that has changed dramatically - which it has - provide documentation on how to do that. For the record, based on my CSLA2 experience, I would have paid significantly more for the latest version.

We're not ALL software engineers, otherwise we'd all be writing frameworks. I'm, a humble developer who has had success using the earlier versions of the framework, and now wants to maybe open some more doors by using the current technology. The simplest way for me to do that is to be given a code sample - as you have just done - rather than trying to "guess" my way around the various components of the new model.

I apologise for my "outburst", but as I didn't think my original post warranted anything more than a reworked example in CSLA4. (That was the purpose of me posting my CSLA2 code). Instead, I ended up in a downward spiral of trying to understand this, that and the other. That IS frustrating.

My original post revolved around the issue of not being able to access the private smartdate attributes of my string property when referenced in my Dal. I will review your example, and hopefully it wil translate to what I'm actually doing.

Thank you.

Graham

gajit replied on Tuesday, February 28, 2012

Nope, Sorry.

I guess I shall go back to the books.

Having selected the encapsulated invoke model using datareader, I don't understand where the "factory" class sits in my structure.

Maybe it's the terminology, but I thought "factory" implementation was a different model.

I have three distinct classes/interfaces when I'm building a BO;

IPersonDal - the interface in my DataAccess project that defines the dataaccess layer

PersonDal - in my DataAccess.SQL project that contains my Fetch, Insert, Update, etc methods, which implements IPersonDal and interacts with the database

PersonEdit - my BO that defines the properties of my object and contains the DataPortal_xxx methods

As I said, I'm going back to the books.

If it's not possible for me to do what I need to do using the encapsulated invoke model, I'd appreciate it if you could just let me know, so I'm not heading off on a wild goose chase.

Thanks,

Graham

 

 

RockfordLhotka replied on Tuesday, February 28, 2012

So you want this:

  class Program
  {
    static void Main(string[] args)
    {
      var obj = DataPortal.Fetch<Test>(123);
      Console.WriteLine(obj.Date);
      Console.WriteLine(obj.IsDirty);
      Console.ReadLine();
    }
  }

  [Serializable]
  //[Csla.Server.ObjectFactory(typeof(TestFactory))]
  public class Test : BusinessBase<Test>
  {
    public static readonly PropertyInfo<SmartDate> DateProperty = RegisterProperty<SmartDate>(c => c.Date);
    public string Date
    {
      get { return GetPropertyConvert<SmartDate, string>(DateProperty); }
      set { SetPropertyConvert<SmartDate, string>(DateProperty, value); }
    }

    public void DataPortal_Fetch(int id)
    {
      using (BypassPropertyChecks)
      {
        LoadProperty(DateProperty, new SmartDate("1/1/10"));
      }
    }
  }

The only thing is that you'll get that date value back from your DAL instead of using a hard-coded value.

The DAL doesn't (shouldn't anyway) be interacting with the object directly. Instead, the object interacts with the DAL and gets the data from the DAL and then sets its own properties.

The whole point of the models shown in the Data Access book is to avoid breaking encapsulation. That means having the DAL get and return data, and the business object set its own properties.

In the case of a conversion property (where the property type and backing value type don't match) you need to use LoadProperty as shown here to set the backing field directly instead of setting the property.

gajit replied on Tuesday, February 28, 2012

Yep, i got that.

But my initial problem is that my Date property is a string and the code that implemements with the command,

cm.parameters.addwithvalue("@mydate, date)

does not expose a '"dbvalue" on the date property - because it's a string. i can't access the underlying smartdate using the model i''m using... and that's where Jonny's responses begun to send me off on a downward spiral.

Can I only do this with a factory implementation?

Thanks,

Graham

 

 

JonnyBee replied on Wednesday, February 29, 2012

Which is why I tried to show you how to either

ObjectFactory class is a base class that exposes some of the inner workings of the <bo> for properties and "state" management when the data access is not don inside the DataPortal_XYZ methods of the <bo>.

Do not confuse this with the ObjectFactory Pattern - that is s separate approach to move absolutely all data access away from the <bo>.
With this pattern there will be no DataPortal_XYZ of Child_XYZ methods in the <bo>.

How hard is this:

Public Class MyDalClass
	Inherits ObjectFactory
	Implements ICodeDal


' implement Dal methods from ICodeDal
' Code has access to ReadProperty(obj, propertyInfo) and LoadProperty(obj, propertyInfo) and more to get the underlying data value from obj
' such as a SmartDate when DAL code is outside of business object.
 End Class

 

RockfordLhotka replied on Wednesday, February 29, 2012

In the code I just posted, notice that LoadProperty takes a SmartDate value, not a string. The corresponding ReadProperty call would return a SmartDate.

That is the value you'd pass to your DAL, not a string. I am not seeing the issue here?

gajit replied on Wednesday, February 29, 2012

Thanks gents,

I really do appreciate the time taken to help out here (despite what might seem otherwise). I'll have another go this morning and see what prevails and let you know.

Graham

 

 

gajit replied on Wednesday, February 29, 2012

OK.

So Jonny, I still wasn't able to implement ReadProperty as per your example using inheritance from ObjectFactory - but at least I'm clear now that there is no conenction between this and the factory model. I couldn;t implement ReadPeoprty because it accepts two parameters, one of which is still the underlying 'property' - which I'm still sure I can't access.

But Rocky,

Of course -  It works.

I had actually by luck rather than judgement already gone down that path. By changing the parameters to the Insert() and Update() methods to Smartdate types, my Dal accesses the smartdate values - and I guess the Getpropertyconvert and setpropertyconvert ensure that the values are maintained correctly through the string->smartdate and smartdate->string changes.

That's the solution I was looking for!

My apologies again for coming across as an insufferable a**hole. This process can be frustrating for me at times and rather than mellowing with age I think I'm suffering from some distorted sense of entitlement and I shall attempt to convey my frustrations in a more constructive manner.

Thanks again.

Graham

 

JonnyBee replied on Wednesday, February 29, 2012

ReadProperty and LoadProperty accepts the BusinessObject as first parameter and the second parameter is the static PropertyInfo.

gajit replied on Wednesday, February 29, 2012

Jonny,

Although I've resolved this with the solution Rocky provided, I'd still like to know how you implement this.

By inheriting the Objectfactory I can indeed use the ReadProperty() method, but what "static PropertyInfo" do you mean?

The only thing I can access from my DAL is the property name passed to the update method, so in this case, my AddDate is available. I cannot reference the static AddDateProperty - that was the whole point of the post.

If I'm misunderstanding your explanation, please provide me with the code you would expect use.

Thanks,

Graham

 

 

Copyright (c) Marimer LLC