处理实体对象设计中的id

时间:2011-05-17 14:20:09

标签: c# .net database entity class-design

有一段时间我一直在考虑如何处理由数据库分配标识符的对象。

表示表实体的典型对象可能如下所示:

public class Test
{
    public int Id { get; private set; }
    public string Something { get; set; }
}

假设我们希望使用此对象来插入,检索和更新数据库中的对象。至于检索和更新,我们没有问题,因为Id字段总是有一个值。

但是,如果我们要将Test类型的新对象插入数据库,则Id字段仍需要具有值。我们可以使用“0”,因为它不太可能被用作数据库密钥,但实际上这不是一个好的设计。

同样,如果我们反转情况并使Id属性可以为空,我们可以对数据库尚未分配标识符的对象使用null。但是,现在可以从数据库中检索的对象没有标识符(如类设计所允许,但不是数据库设计)

关于如何为这个问题做好设计的任何好主意?

3 个答案:

答案 0 :(得分:3)

如果您将id视为在应用程序中识别/授予对象唯一性的方法,则应由数据库处理(除非当然,您还有其他方式来分配标识符对象)。

如果不是(因为它的对象的属性由业务需求驱动) - 0是否有效/良好的设计价值取决于纯粹的业务需求。从最终用户的角度来看,0是否有效值?

如果您认为在应用程序中设置了没有ids的对象是有问题的,您始终可以将对象属性包装到单独的类中。您将使用此类主要仅用于携带尚未创建的对象的参数(创建过程使用数据库插入完成)。一旦插入对象,id分配和填充 - 您可以使用常规实体。您的用户是否会“哦,快攻!这是什么?”“好的......我知道该怎么做。”一旦被id = 0接近?< / p>

修改

这个问题(或者说我关于包装参数的答案)让我想起曾经让我感到惊讶的事实。当孩子出生时,在她的父母正式注册她并且她获得个人识别号码之前,她不存在于系统中。所以在技术上,没有id - 孩子不存在(至少从系统的角度来看),即使是每个人都知道她出生了。与数据库/您的应用程序相同 - 没有id的对象(数据库无法识别的对象)不存在 - 它只是一组参数。有点古怪,但我希望我的观点很清楚:)

答案 1 :(得分:3)

设计类没有任何问题,因此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;
    }
} 

答案 2 :(得分:1)

因此,您有一个包含数据库表标识符的类作为字段,因此在检索/删除和更新的情况下,您的实体的标识符与数据库记录的标识符对齐。如果插入,您可以检索刚刚插入的记录的标识值,并使用该值更新您的实体。因此,您可以使用单独的存储过程来插入/更新/检索和删除。插入SP可以返回刚插入out parameter的记录的ID。希望我回答你的问题。