Business Object - Required Fields

Business Object - Required Fields

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


Aver posted on Friday, June 06, 2008

Hello All,
   This is my first project using CSLA.net and I love this architecture. This is exactly what I needed coming from my CS Object Oriented background into the wonderful relational database business software world.

My question is in regards to the proper approach to take with business objects that have required fields. I am making a Employee object that has 3 required fields in the database. You can see the table definition below. I created the following methods:

public static Employee NewEmployee(string FirstName, string LastName,string EmployeeNumber)
{
            return DataPortal.Create<Employee>(new Criteria(FirstName,LastName,EmployeeNumber));
}

 [RunLocal()]
protected void DataPortal_Create(object criteria)
{
            FirstName = ((Criteria)criteria).FirstName;
            LastName = ((Criteria)criteria).LastName;
            EmployeeNumber = ((Criteria)criteria).EmployeeNumber;
           
            using (var ctx = ContextManager<DalLinq.ESMDataContext>.GetManager("ESM"))
            {
                int? newId = null;               
                ctx.DataContext.AddEmployee(FirstName,LastName,EmployeeNumber,ref newId);
                _id = System.Convert.ToInt32(newId);
                //FieldManager.UpdateChildren(this);
     }
}

Employee Table
ID int identity(1,1),
FirstName varchar(50) not null,
LastName varchar(50) not null,
EmployeeNumber varchar(6) not null



Is it wrong to even include a NewEmployee method? Should I simply create the object initialize the values and then call the insert/save method to persist the object to the database? My concern is that the ValidationRules are not being checked this going through the NewEmployee method. I could validate the input in the NewEmployee method but I am not sure if that is the ideal approach, since I have validation rules for each field.

ajj3085 replied on Friday, June 06, 2008

Hi, and welcome.

Well, if you're use case requires that you have a way to create new employees, then having a NewEmployee method is totally fine. 

A few things though... do you really want to create the new record in the database right away?  Normally you'd return the new, empty object for your users to edit.  Then decide whether not to save. 

Also, since you're talking to the database, you really shouldn't have the RunLocal attribute.  Use that attribute when you DON'T talk to the database in a DataPortal method.  The reason is that if you move to three tier, the presense of that attribute will stop that immediately... your BO is talking directly to the DB from the client.

Regarding rules, you can call ValidationRules.CheckRules before the dataportal create finishes.  That will run any rules you have setup for the type. 

Oh, one last thing.. since you're using the Generic version of DataPortal.Create<T> your criteria should be of type Criteria, not "object."

HTH
Andy

Aver replied on Friday, June 06, 2008

I guess the reason that I wanted to create the object in the database right away was to generate the ID value for the object. The employee object will have a child collection so I thought it would be important to generate the ID for those objects.  How would the child objects know the link between them and the parent if the ID value is null? (I am starting to see the advantages of GUID but I still perfer the ID)

Thanks for the very fast reply and great help.

Michael Hildner replied on Friday, June 06, 2008

Apologies for jumping in...

Assuming you're using sprocs and MSSQL, you can use an ouput parameter, and set it to @@IDENTITY (I think it's @@IDENTITY - I don't use IDs much). That way when you save your parent, you get back the ID.

IIRC, the PTracker code uses this approach - I'm sure I've seen it in the book anyway.

If that doesn't make sense I can dig up some code examples.

Regards,

Mike

ajj3085 replied on Friday, June 06, 2008

It looks like you're using Linq, correct?

If so, something like this in your DataPortal_Insert will work:

Data.Employee emp = new Data.Employee();

emp.FirstName = firstName;
emp.LastName = lastName;
emp.EmployeeSSN = empSSN;
emp.PropertyChanged +=
    delegate( object sender, PropertyChangedEventArgs e ) {
          if ( e.PropertyName == "EmployeeId" ) {
               employeeId = emp.EmployeeId.Value;
          }
    };
db.Employee.InsertOnSubmit( emp );

children.Save( emp );
db.SubmitChanges();
  

In your child object, you would do this:

DataPortal_Insert for child
Data.ChildData data = new Data.ChildDate();
data.Employee = emp;
data.SomeField = someField;

db.ChildData.InsertOnSubmit( data );


That gives you the general idea.. the code is certainly missing in most places, but you should be able to get the idea.

Also, if you're using Linq, be sure to listen for PropertyChanged events as I did in the parent.. otherwise your BO won't know the generated id.  You'll need to do that for children BOs as well.

Copyright (c) Marimer LLC