如何在面向对象的代码中设置ID

时间:2009-10-18 16:53:31

标签: .net oop design-patterns

对于3层应用程序来说,面向对象编程时我有点困惑。这只是我想要做的一个小例子(我将缩短数据库设计以使其变得简单)。假设我正在制作票务服务台系统。机票有说明,负责人,截止日期,当然还有ID(唯一)。

假设ID只是一个类型为integer的IDENTITY列,并自动获取其值(SQL Server)。也就是说,只有在插入完成后才能获得它的值。

现在只是一些示例伪代码(可能不对,所以不要让语法错误,只是试图得到关于如何存储ID的答案)。

我可以轻松创建Ticket类

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?
 }

好吧我有这个名为ticket的类..但是当我创建一个票对象并需要从我的BLL(业务逻辑层)插入它时会发生什么

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);

//将它传递给BLL,它做了它的事情,并将它传递给DAL做一个INSERT语句,然后返回数据库给它的ID号。

所以我的问题是我需要如何或何时分配t.ID,或者我甚至需要在插入后给出我已完成。我总是对OOP感到困惑,因为我倾向于认为它使事情更复杂,然后传递一大堆参数。

好的,所以有人可以帮我理解我是否需要获取/设置ID以及是否应该将该值传递回我的界面。我的第二个问题是更新? 假设最终用户找到了一张票,所以在我的界面上我检索了一些票据数据,有人想要更新说明说明和截止日期。当我“提交”这些更改时,我应该只创建一个故障单对象,设置所有get / set属性值,那就是它吗?或者我应该只将身份证号码和所有参数传递给我的BLL并让它全部处理?

希望这一切都有意义!

非常感谢你们!

6 个答案:

答案 0 :(得分:1)

答案是它取决于您使用的框架或库。

并非所有BLL都允许您简单地说Ticket t = new Ticket(),您可能必须使用t = b.CreateTicket()或其他内容。 Id可以是临时值,也可以只是null / 0,直到它被持久化。

关于问题的第二部分:

如果您想要更新故障单,您当然创建新的故障单对象。您更新现有对象。

也许你应该根据特定的图书馆或技术澄清或重新提出这个问题。

答案 1 :(得分:1)

通常我会使用某个键值(即-1)作为默认的未保存ID。 然后,这将被传递到上游到将保存此对象的相关DB层 并更新ID并在必要时返回(如果需要,还可以更新最终客户端请求)。 我经常将键默认为构造对象时的默认值。

在以前的一些项目中,我使用Guid作为密钥,因为它们可以在客户端/应用程序服务器上生成,而不需要密钥生成所需的数据库(以及随后更新父对象的外键)。这可以在执行SQL时节省相当多的时间,因为它可以更容易地批处理)。如果需要,可以使用Guid Comb来更快地生成密钥。但是,如果您需要增量键,则可能无法选择此项。

根据框架/技术/基础设施......这可能会有所不同......

答案 2 :(得分:0)

使用NHibernate或其他一些像样的O / R Mapper,你甚至不会遇到这个问题。该属性可以是只读的,并在插入之前或之后由ORM本身设置。除此之外,如果您是手动执行此操作,则可以将其设置为只读并使用少量反射在需要时从DAL设置ID而不会违反封装。

顺便说一下,为什么要将对象传递给BLL?对象本身不应该实现自己的业务逻辑吗?这就是制作物品的关键。否则,您应该只使用强类型数据集。听起来你正在做“贫血领域模式”,这很糟糕:

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

答案 3 :(得分:0)

也许此列表可以帮助您:

    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() {}
    }

答案 4 :(得分:0)

您可以尝试这样的事情。代码并不完美,但它会给你一个想法。对不起,我试图让这个比我应该更快,所以它非常粗糙。

// 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

答案 5 :(得分:0)

几点:

1 - 匈牙利的表示法是1985年的老兄。 :)

2 - 你在这里重新发明轮子。有许多好的ORM frameworks以一种很好的标准化方式处理持久性,让你继续编写你的域。

3 - 好的,所以如果你绝对不能使用像NHibernate这样的ORM框架,或者上帝禁止实体框架,那么我建议你遵守ORM框架使用的标准模式之一,比如{ {3}}或ActiveRecord。是的,您需要在保留新对象后分配DataMapper。 Martin Fowler的ActiveRecord和DataMapper模式都使用“插入”方法将新对象持久化到数据库。在像Rails这样的其他ORM框架中,使用了“save”,并且新的Object可以通过调用诸如“new_record?”之类的接口来报告它是否已被持久化。返回TRUE直到调用“save”或“insert”。在调用其中一个方法之前,ID字段通常默认为0或-1,两者都是无效的PKID。在“插入”或“保存”内,检索新的id字段并将其分配给新对象的id字段。