How to set ID in Object Oriented Code
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; }
开发者_JS百科 }
//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!
The answer is that it depends on the Framework or Library you are using.
Not all BLL's let you simply say Ticket t = new Ticket()
, you may have to use t = b.CreateTicket()
or something. The Id can be a temporary value or simply null/0 until it is persisted.
On the second part of your question:
If you want to update a Ticket you certainly don't create a new Ticket object. You update the existing object.
Maybe you should clarify or re-ask the question in the light of a specific library or technology.
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...
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
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() {}
}
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
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.
精彩评论