0

我正在创建一个网站,数据将从一个外部应用程序发送,该应用程序具有一个充满数据的数据库,网站只需要其中的一部分。“部分”是指每个表中的一些行,但不是全部。

手头的业务是管理慈善券的业务,他们有客户,他们有账户。慈善机构可能希望登录该网站并查看有关支付给他们的款项的信息,而客户可能希望登录并查看有关其帐户的信息。

但是,想要在线登录的客户数量仅占拥有帐户的客户的一小部分。我们希望避免上传所有客户和慈善机构信息,因为这将是大量数据,必须保持最新,而且大部分不会被使用。

当我们有一张已发行的代金券,但客户的账户中没有足够的钱来支付它时,就会出现问题。在这种情况下,代金券被保留,等待客户存款。慈善机构希望查看持有的代金券列表,但不会显示客户姓名,他们只看到代金券的详细信息,例如日期、金额和编号。

理想情况下,我希望网站数据库是完全相关的,但这会导致数据丢失的问题。例如,如果我们上传持有凭证的详细信息,而客户的详细信息不在网站数据库中(因为他们无法通过网站访问),那么作为外键引用,插入到 HeldVouchers 表将失败客户表将指向不在数据库中的客户。

我可以使所有外部引用都可以为空,但这仍然没有帮助,因为客户 ID 不会为空,它将包含主数据库中客户的 ID。

我可以在上传时检查,如果为不在数据库中的客户上​​传了持有的凭证,那么我可以将 CustomerID 设置为空。这很好,但如果该客户随后想要访问该网站,并且我们上传了他的详细信息,那么我们将不得不更新 HeldVouchers 表。这将导致大量额外的工作,以及大量的额外上传。

有人知道如何处理这个问题吗?到目前为止,我唯一的想法是使 Web 数据库完全非关系(我真的不喜欢这样做),然后将扩展方法添加到将模拟 EF 生成的实体的实体中,除非它们会直接转到适当的 DbSet 并拉出与“外键”引用匹配的任何实体。

我尝试了这个,并提出了一个有效的通用扩展方法,但至少有两个非常严重的缺点......

public static List<T> NavColl<T>(this EntityInterface entity, Func<T, bool> f)
  where T : class, EntityInterface {
  return Ctx.Set<T>().ToList().Where(f).ToList();
}

(此方法返回相当于一个集合的导航属性。我有一个类似的查找单个实体的方法)。

如果你有一个 Charity 对象(巧妙地命名为“charity”),并且想要获得持有的代金券,你可以做这样的事情......

charity.NavColl<HeldVoucher>(ca => ca.CharityID == charity.ID)

第一个缺点是,我能看到允许将 Func 传递到扩展方法中并且不让 Linq-To-Entities 抛出杂乱无章的唯一方法是在应用 Func之前枚举 DbSet 。如果那里有很多数据,这可能会显着减慢查询速度。

也许更严重的(因为我不认为性能是一个主要问题)是扩展方法需要一个可以工作的上下文。目前,我将实体放在与 EF 模型不同的项目中,因为这允许我引用解决方案中任何项目的实体,而这些项目不需要引用模型的项目。这有助于保持层分离,并允许测试等。

但是,如果扩展方法需要上下文,则实体项目需要对模型项目的引用,这会导致循环引用(因为模型需要了解实体)。我不能将扩展方法放在模型项目中,因为那样我必须从每个想要使用实体的项目中引用它,这违背了将实体拆分到自己的项目中的整个目的。

有人有什么想法吗?抱歉,这是一个有点长的问题,但我想确保我清楚地解释了这个问题。

4

1 回答 1

2

我们遇到的第一个问题是术语。缺少外键的数据库不是非关系型的。它仍然是一个关系数据库,只是没有 DRI(声明性引用完整性)。

我认为在可能丢失数据的情况下,您将不得不设计没有外键的数据库。不过,这不会阻止您在 EF 中定义这些实体之间的关系。我们一直这样做。您没有说明您使用的是 EDMX 还是 Code First。我们使用 EDMX,过去我们所有的实体都映射到视图。就 EF 而言,我们的数据库中没有外键关系(因为视图映射),所以我们只是自己绘制它们,并且我们在实体之间获得了完整的导航属性支持。

于 2014-03-12T16:41:21.670 回答