C# 处理id';实体对象设计中的s
一段时间以来,我一直在思考如何处理由数据库分配标识符的对象 代表表格实体的典型对象可能如下所示:C# 处理id';实体对象设计中的s,c#,.net,database,entity,class-design,C#,.net,Database,Entity,Class Design,一段时间以来,我一直在思考如何处理由数据库分配标识符的对象 代表表格实体的典型对象可能如下所示: public class Test { public int Id { get; private set; } public string Something { get; set; } } 假设我们想使用这个对象在数据库中插入、检索和更新对象。至于检索和更新,我们没有问题,因为Id字段总是有一个值 但是,如果我们想在数据库中插入一个新的Test类型的对象,Id字段仍然需要有一个值
public class Test
{
public int Id { get; private set; }
public string Something { get; set; }
}
假设我们想使用这个对象在数据库中插入、检索和更新对象。至于检索和更新,我们没有问题,因为Id字段总是有一个值
但是,如果我们想在数据库中插入一个新的Test类型的对象,Id字段仍然需要有一个值。我们可以只使用“0”,因为它不太可能用作数据库密钥,但实际上这不是一个好的设计
类似地,如果我们颠倒情况并使Id属性为null,那么对于数据库尚未分配标识符的对象,我们可以使用null。但是,现在从数据库检索的对象可能没有标识符(类设计允许,但数据库设计不允许)
关于如何对此问题进行良好设计,有什么好主意吗?因此,您有一个包含数据库表标识符作为字段的类,因此在检索/删除和更新时,您的实体标识符将与数据库记录的标识符对齐。在插入的情况下,您可以检索刚刚插入的记录的标识值,并用该值更新实体。因此,您可以使用单独的存储过程来进行插入/更新/检索和删除。插入SP可以返回刚刚作为
输出参数插入的记录的id
。希望我能回答您的问题。如果您将id
视为在应用程序中标识/授予对象唯一性的一种方法,则这应该由数据库处理(当然,除非您有其他方法为对象分配标识符)
如果不是(例如,它是由业务需求驱动的对象属性)0是否有效/良好的设计值完全取决于这些业务需求。从终端用户的角度来看,0
是否有效
如果您觉得在应用程序中设置没有id
的对象是有问题的,那么您总是可以将对象属性包装到单独的类中。实际上,您将只使用此类类来承载尚未创建的对象的参数(创建过程将通过数据库插入完成)。一旦对象被插入,id被分配和填充-你可以使用你的常规实体。当您的用户被id=0
接近时,是否会说“哦,snap!那是什么?”或“Ok..我知道该怎么做”
编辑
这个问题(或者说我关于包装参数的回答)提醒了我一个曾经让我吃惊的事实。当一个孩子出生时,她并不存在于系统中,直到她的父母正式为她登记,并为她分配了个人身份号码。所以从技术上讲,如果没有id,孩子是不存在的(至少从系统的角度来看是这样),即使每个人都知道她出生了。数据库/你的应用程序也是如此——没有
id
(数据库无法识别的对象)的对象不存在——它只是一组参数。有点奇怪,但我希望我的观点是清楚的:)设计一个ID为0的类并没有错,它表示实体还没有被序列化。我曾经构建过成功使用这种方法的系统。只需确保这些语义在API中定义良好,并且所有代码都尊重这些语义
需要注意的一个陷阱是使用ID定义相等关系(例如为字典生成哈希代码)。只能对非零ID执行此操作。对于测试两个ID为零的相等性,可以使用引用相等性
但是,由于未存储的实体在将来的某个时候可能会更改其ID,因此绝对不要将此类对象存储在字典中,这一点非常重要。或者,至少在保存之前必须从任何字典中删除这些项,然后使用新ID恢复
有了这个保留,这个设计应该可以很好地工作
public class Test : IEquatable<Test>
{
/// <summary>
/// The unique identifier for this Test entity, or zero if this
/// Test entity has not yet been serialized to the database.
/// </summary>
public int Id { get; private set; }
public string Something { get; set; }
public override bool Equals(object obj)
{
return Equals(obj as Test);
}
public bool Equals(Test other)
{
if (other == null)
return false;
// Distinct entities may exist with the Id value of zero.
if (Id == 0)
return object.ReferenceEquals(this, other);
return Id == other.Id;
}
/// <summary>
/// Gets a hash code for this Test entity. Warning: an instance with
/// an Id of zero will change its identity when saved to the DB. Use with care.
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode()
{
return Id;
}
}
公共类测试:IEquatable
{
///
///此测试实体的唯一标识符,如果是,则为零
///测试实体尚未序列化到数据库。
///
public int Id{get;private set;}
公共字符串Something{get;set;}
公共覆盖布尔等于(对象对象对象)
{
返回等于(obj作为测试);
}
公共布尔等于(测试其他)
{
如果(其他==null)
返回false;
//Id值为零的不同实体可能存在。
如果(Id==0)
return object.ReferenceEquals(this,other);
返回Id==other.Id;
}
///
///获取此测试实体的哈希代码。警告:具有
///Id为零将在保存到DB时更改其标识。请小心使用。
///
///散列码。
公共覆盖int GetHashCode()
{
返回Id;
}
}
如果从数据库检索对象,则无法获取没有标识符的对象。。当你插入它时,它会立即得到一个id(除非你有一个真正奇怪的数据库)@xs0。但是,严格地看对象类型定义,这是可能的。好吧,你的问题正好相反。。但不管怎样,你想用这些东西做什么?除非你解释将使用它们执行哪些操作,否则问题就不清楚了。你是在使用实体框架还是你只是指一般意义上的“实体”?我指的是一般意义上的实体,尽管在使用实体框架时问题显然也存在。我同意Abdul的说法,db有责任确定新的ID值,并为新记录设置任何其他合适的默认值。您需要从db请求一个新行,然后允许用户修改t