对于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并让它全部处理?
希望这一切都有意义!
非常感谢你们!
答案 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?对象本身不应该实现自己的业务逻辑吗?这就是制作物品的关键。否则,您应该只使用强类型数据集。听起来你正在做“贫血领域模式”,这很糟糕:
答案 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字段。