【问题标题】:C# Objects, Interfaces and the DatabaseC# 对象、接口和数据库
【发布时间】:2010-09-29 02:18:05
【问题描述】:

在使用对象和接口时,写入数据库的最佳实践是什么?关于对象设计有很多意见,但我不清楚数据库端。一个简单的例子:

假设一个 Contact 基类包含常用字段,例如联系人姓名(Bill、Fred、Sally)和位置(家庭、工作等)。添加一个 IPhone 接口(区号、电话号码、分机)和一个 IEmail 接口(电子邮件地址,cc)以抽象出差异。然后创建继承自这些的类(电话、电子邮件),如下所示:

电话:联系方式,IPhone 电子邮件:联系方式,IEMail

另一种方法是创建一个 IContact 接口而不是 Contact 基类,如下所示:

电话:IContact、iPhone 电子邮件: IContact、IEMail

没有实现 NHibernate 或 Entity Framework 如果这些对象被写入单个数据库表,那么数据访问代码的最佳实践是什么?我所看到的似乎相当笨拙。

【问题讨论】:

  • 如果联系人有电话和电子邮件怎么办?联系人应该有一个包含所有电话数据的电话字段和一个包含所有电子邮件数据的电子邮件字段。您甚至可能想要拥有多个电话或电子邮件;但是电话不是联系人,那为什么电话类要扩展联系人呢?

标签: c# database object interface


【解决方案1】:

在这种情况下...我认为最好的选择是使用数据库对象,例如 DB4O。

“Db4o 是开源对象数据库,它使 Java 和 .NET 开发人员能够存储和检索任何应用程序对象,包括主题地图,只需一行代码,无需预定义或维护单独的、严格的数据模型。”

http://www.db4o.com/

【讨论】:

    【解决方案2】:

    听起来您要建模的是电话联系人和电子邮件联系人,但我认为您真正拥有的是具有主要联系方式的联系人:电话或电子邮件。我构建它的方式是组合——假设您希望灵活地拥有多个电话号码/电子邮件。如果每个人都可以使用一个,则可以将其直接存储在联系人表中。如果您需要多个地址,则使用与电话/电子邮件相同的方式处理它,并使用单独的表格。

    联系人表 联系人 ID 名 姓 心肌梗死 街道地址1 街道地址2 城市 州省 邮政编码 PreferredContactMethod(0 = 电话,1 = 电子邮件) ... 更多细节 ... 电话号码表 电话号码 联系人 ID 电话号码 是主要的 ...更多细节... 电子邮件地址表 电子邮件ID 联系人 ID 电子邮件地址 是主要的 ...更多细节...

    那么,对于您的类,您将拥有一个 Contact 类,其中包含一个或多个 PhoneNumbers 和一个或多个 EmailAddresses。如果除了联系人之外,您还有其他的东西有电话号码或电子邮件地址,那么让界面指示它们是 IPhoneable 或 IEmailable 可能是有意义的——这意味着您可以从中添加/删除电话号码或电子邮件地址,就像这样:

    public interface IPhoneable
    {
         public PhoneNumber GetPrimaryNumber();
         public void AddNumber( PhoneNUmber number );
         public IEnumerable<PhoneNumber> GetNumbers();
    }
    
    public interface IEmailable
    {
         public EmailAddress GetPrimaryAddress();
         public void AddEmailAddress( EmailAddress address );
         public IEnumerable<EmailAddress> GetEmailAddresses();
    }
    
    public class Contact : IPhoneable, IEmailable
    {
         private List<PhoneNumber> phoneNumbers;
         private List<EmailAddresses> emailAddresses;
    
         public int ContactID { get; private set; }
         public string FirstName { get; set; }
         ...
    
         public Contact()
         {
             this.phoneNumbers = new List<PhoneNumber>();
             this.emailAddresses = new List<EmailAddress>();
         }
    
         public PhoneNumber GetPrimaryNumber()
         {
              foreach (PhoneNumber number in this.phoneNumbers)
              {
                   if (number.IsPrimary)
                   {
                        return number;
                   }
              }
              return null;
          }
    
          ...
    }
    

    如果你愿意,你可以有一个 PhoneableContact 和一个 EmailableContact ,它们可以从 Contact 子类化,并且可以根据首选的联系方式进行区分,但我真的不认为需要这样做。如果你这样做了,那么 Contact 将不会实现任何一个接口——子类将分别实现适当的接口。

    【讨论】:

      【解决方案3】:

      首先构建您的数据库,这样您就可以确定您实际上可以存储您需要的所有内容。然后构建常见查询,例如“所有客户及其主要电话号码”和“单个客户及其所有电话号码”。

      这将暴露出没有足够的电话号码字段或无法指示真实电话号码的明显情况。

      您的数据库的使用时间至少是您的应用程序的三倍,并且很难更改,因此请确保从一开始就做好。

      【讨论】:

        【解决方案4】:

        我猜你需要考虑这三个实体之间的关系。大声说出以下陈述,看看哪些陈述适合您的应用:

        • Phone A Contact
        • Phone A Contact

        从您在此处发布的内容看来,您可以通过使用第二个选项来大大降低应用程序的复杂性。

        但是您对数据访问感到疑惑,并且您提到只有一个数据库表,这让我想知道为什么您需要为 ContactPhoneEmail 提供单独的实体。我建议您重构代码以包含一个实体来表示您的数据模型,因为这将降低代码库的复杂性,或者重构您的数据库模式以反映您真正想要的内容(基于您的示例代码)。

        【讨论】:

        • 实际上,我会反过来想:一个联系人有一个电话。
        • 我一开始也是这么想的,但他的数据模型似乎是相反的。
        【解决方案5】:

        根据我的经验,当涉及到数据库时,如果您想要获得任何表面上的性能,则必须首先考虑良好的关系设计。之后,我的模型就很简单了:一张桌子,一个班级。如果我有自引用关系,我会创建另一个直接从原始类派生的类。连接被定义为对象列表(例如,订单有一个订单详细信息列表)。

        完成此操作后,我将使用能够反映这些类并动态生成所需 SQL 的 DAL;分析后,我可能必须创建一些 SP,但其结果也会发送到接收 DTO。

        到目前为止,我还没有遇到任何使用接口的理由。

        【讨论】:

        • 接口服务器在 DAL 中发挥了出色的作用。您可能会考虑连接所有对象服务并通过接口引用来引用这些服务。这将使模拟变得容易,如果您以后确实需要扩展或远程,您将更容易这样做。
        • 没错,我没有想到它的模拟和远程处理方面。
        猜你喜欢
        • 2010-12-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-10
        • 2018-04-04
        • 2011-06-27
        • 1970-01-01
        相关资源
        最近更新 更多