views:

170

answers:

5

I'm a bit confused when it comes to Object oriented programming for say a 3 tier application. Here is just a small example of what I am trying to do (I will shorten the database design to make it simple). Assume I am making a ticket help desk system. A ticket has a description, a responsible person, a due date, and of course an ID (unique).

Assume the ID is just an IDENTITY column that is of type integer and gets its value automatically (SQL Server). That is it gets its value only after an insert has been done.

Now just some sample pseudo code (it may not be right, so dont let the syntax bug you out, just trying to get an answer about how to store the ID).

I could easily create a Ticket class

public class Ticket
 {
   private string m_description;
   private date m_duedate;
   private string m_responsible;
   private int m_id; //should this be read only ??? or...how

  //then I can have a bunch of Properties to get / set these private variables
   public Property Responsible{
       get 
           { return m_responsible; }
       set 
           { m_responsible = value; }
   }

  //and so on..again dont worry about syntax.  Now should I have a get / set for the ID?
 }

Ok so I have this class called ticket..but what happens when I create a ticket object and need to insert it from my BLL (Business Logic Layer)

Bll b = new Bll();
  Ticket t = new Ticket();
  t.Responsible = someString;
  t.DueDate = someDate;
  t.Description = someLongString;
  //use the BLL to create a ticket object and pass it to the DAL ?
  //then assign the ID from the database to t.ID ???
  t.ID = bll.InsertTicket(t);

//that is pass it to the BLL, which does its thing, and passes it to the DAL does an INSERT statement and then returns the ID number given to it by the database.

So my question is how or when do I need to assign t.ID or do I even need to given after its inserted I am done. I always get confused with OOP because I tend to think it complicates things more then just passing a whole slew of parameters.

Ok so after someone can help me understand whether I need a get/set on the ID and whether I should pass that value back to my interface. My second question is what about updates? Assume an end user finds a ticket, so on my interface I retreive some ticket data and someone wants to update say the description and due date. When I "Submit" these changes, should I just create a ticket object, set all the get / set property values and thats it? Or should I just pass in the ID number and all the paramters to my BLL and let it handle it all?

Hope this all makes sense!

Thanks so much guys!

+1  A: 

Normally I would utilize a certain key value (i.e -1) as the default unsaved ID. This would then be passed upstream to the relevant DB layer that would save this object and update the ID's and return it if necessary (else have the end client request updates if required). I often have the key default to the default value on construction of the object.

On some previous projects I've utilized Guid as keys as they can be generated at the client/application server without the database being required for key generation (and subsequent updating of foreign keys to the parent objects). This can save a fair amount of time in terms of executing the SQL as it can be batched easier). A Guid Comb could be utilized for quicker generation of keys if required. However this might not be an option if you required incremental keys.

This could differ based on frameworks/technologies/infrastructure...

saret
Ok I understand so is it safe to assume I could create a read / write property called ID say. And once I do something like this:ticket t = new Ticket(); the default constructor could set this ID to say -1. Then I fill the rest of the properties and pass it to the Business Logic Layer as a ticket object parameter? And then inside of my BLL I can pass it to my db layer as a ticket object parameter? Is that ok that I am passing the same ticket object from the client code, to the BLL to the DAL. THen I would access the properties and insert the ticket as a record via a sproc and return ID?
A: 

Use NHibernate or some other decent O/R Mapper, and you won't even have this problem. The property can be read-only and set by the ORM itself before or right after the insert. Barring that, if you are doing it by hand, you can make it read only and use a small amount of reflection to set the ID from the DAL when needed without violating encapsulation.

As an aside, why are you passing the object to a BLL? Shouldn't the object itself implement its own business logic? Thats the point of making objects. Otherwise you should just use strongly typed datasets. It sounds like you're doing the "anemic domain model" which is bad:

http://martinfowler.com/bliki/AnemicDomainModel.html

fregas
How else would I get this ticket object to the DAL (data access layer). The interface has no way of accessing the DAL, only through the BLL
A: 

Maybe this listing will help you:

    public class Ticket : IEquatable<Ticket>
    {

     public static Ticket Create()
     {
           return new Ticket { Id = Guid.NewGuid() };
     }

     /// Id must be really unique
     public Guid Id {get; private set;}

     /// other properties
     /// ...

     bool IEquatable.Equals(Ticket ticket)
     {
           return ticket != null && ticket.Id == this.Id;
     }

     /// hidden ctor
     protected Ticket() {}
    }
madcyree
A: 

You might try something like this. The code isn't perfect, but it'll give you an idea. Sorry, I'm trying to make this quicker than I should, so it's very rough.

// returns Record number of object
public int Insert()
{
  SqlConnection conn = new SqlConnection(dbstring);
  SqlCommand insertCommand = new SqlCommand("mystoredprocedure");
  SqlParameter newRecNo = new SqlParameter();
  newRecNo.Direction = ParameterDirection.ReturnValue;
  conn.Open();
  insertCommand.ExecuteNonQuery();  // Your sqlparameter will now contain the recno
  conn.close(); // use try/catch, etc.
  return newRecNo.value;
}
public static MyObject GetData(int TicketID)
{
  // Get object data from DB.
}

In the stored procedure to insert, put this in:

declare @recno int
set @recno =  @@identity
return @recno
Serinus
A: 

A few points:

1 -- Hungarian notation is sooo 1985 dude. : )

2 -- You are reinventing the wheel here. There are lots of good ORM frameworks that handle persistence in a nice standardized way and let you get on with writing your Domain.

3 -- Ok, so if you absolutely CAN'T use an ORM framework like NHibernate, or, God forbid, Entity Framework, then I would suggest you adhere to one of the standard patterns that the ORM frameworks use, like ActiveRecord or DataMapper. Yes, you need to assign the Identity Field after a new object has been persisted. Martin Fowler's ActiveRecord and DataMapper patterns both use an 'insert' method to persist new Objects to the database. In other ORM frameworks like Rails a similar method, 'save' is used, and a new Object can report whether it has been persisted by calling an interface such as 'new_record?' which returns TRUE until 'save' or 'insert' is called. Until one of those methods is called, the ID field is usually defaulted to 0 or -1, both invalid PKIDs. Within 'insert' or 'save' the new id field is retrieved and assigned to the id field of the new object.

Dave Sims