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