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

.net 如何在面向对象代码中设置ID,.net,oop,design-patterns,.net,Oop,Design Patterns,当涉及到面向对象编程(比如说三层应用程序)时,我有点困惑。这里只是我尝试做的一个小例子(我将缩短数据库设计以使其变得简单)。假设我正在制作一个票务服务台系统。票证有描述、负责人、截止日期,当然还有ID(唯一) 假设ID只是一个integer类型的标识列,并自动获取其值(SQL Server)。也就是说,它只有在插入完成后才获得其值 现在,只需一些示例伪代码(可能不正确,所以不要让语法困扰您,只是尝试获得有关如何存储ID的答案) 我可以很容易地创建一个票证类 public class Ticket

当涉及到面向对象编程(比如说三层应用程序)时,我有点困惑。这里只是我尝试做的一个小例子(我将缩短数据库设计以使其变得简单)。假设我正在制作一个票务服务台系统。票证有描述、负责人、截止日期,当然还有ID(唯一)

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

现在,只需一些示例伪代码(可能不正确,所以不要让语法困扰您,只是尝试获得有关如何存储ID的答案)

我可以很容易地创建一个票证类

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的类。但是当我创建一个ticket对象并需要从BLL(业务逻辑层)插入它时会发生什么呢

//也就是说,将它传递给BLL,由BLL完成它的工作,然后通过INSERT语句将它传递给DAL,然后返回数据库给它的ID号

所以我的问题是,我需要如何或何时分配t.ID,或者在插入t.ID之后,我甚至需要给出t.ID。我总是对OOP感到困惑,因为我倾向于认为它比仅仅传递一系列参数更复杂

好的,在有人帮助我了解我是否需要ID上的get/set,以及我是否应该将该值传递回我的接口之后。我的第二个问题是更新怎么办? 假设最终用户找到了一张票证,那么在我的界面上,我检索了一些票证数据,有人想要更新,比如说描述和截止日期。当我“提交”这些更改时,我是否应该创建一个ticket对象,设置所有get/set属性值,就这样?或者我应该把ID号和所有参数传递给我的BLL,让它处理所有的事情吗

希望这一切都有意义


非常感谢各位

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

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

关于你问题的第二部分:

如果要更新票证,您肯定不会创建新的票证对象。更新现有对象


也许你应该根据特定的库或技术来澄清或重新提问。

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

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


这可能因框架/技术/基础设施的不同而有所不同。

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

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


也许此列表将帮助您:

    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() {}
    }
公务舱票:可接受
{
公共静态票证创建()
{
返回新票证{Id=Guid.NewGuid()};
}
///Id必须是唯一的
公共Guid Id{get;private set;}
///其他属性
/// ...
bool IEquatable.Equals(票证)
{
回程票!=null&&ticket.Id==this.Id;
}
///隐藏的导体
受保护的票证(){}
}

您可以尝试这样的方法。代码并不完美,但它会给你一个想法。对不起,我正试图让这比我应该做的要快,所以这很艰难

// 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
有几点:

1--is sooo 1985 dude.:)

2--你在这里重新发明轮子。有很多好的方法可以以标准化的方式处理持久性,让您能够继续编写域


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

@Peter Lillevold的编辑:“Oriented”是不太常用的英国拼写;这不是一个错误。对不起,这没有意义。为什么要从中创建票证
// 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