我正在创建一个网站,数据将从外部应用程序发送,该外部应用程序的数据库中包含数据,网站只需要部分数据。 “部分”是指每个表中的一些行,但不是全部。
手头的业务是管理慈善券的业务,他们拥有与他们有账户的客户。慈善机构可能希望登录该网站并查看有关支付给他们的资金的信息,客户可能希望登录并查看有关其帐户的信息。
但是,想要在线登录的客户数量只占拥有帐户的客户的一小部分。我们希望避免上传所有客户和慈善机构信息,因为这将是大量数据,这些数据必须保持最新,而且大部分都不会被使用。
如果我们有一张已经签发的凭证,但是客户的帐户中没有足够的资金来支付它,则会出现问题。在这种情况下,凭证被保留,等待客户存款。慈善机构希望查看持有的优惠券清单,但不会显示客户名称,只会看到凭证详细信息,例如日期,金额和数量。
理想情况下,我希望网站数据库是完全关系的,但这会导致数据丢失的问题。例如,如果我们上传持有的凭证的详细信息,其中客户的详细信息不在网站数据库中(因为他们无法通过网站访问),那么插入HeldVouchers表将失败,因为外键引用到Customers表将指向不在数据库中的客户。
我可以使所有外部引用都可以为空,但这仍然没有帮助,因为客户ID不会为null,它将包含主数据库中客户的ID。
我可以检查上传时间,如果为不在数据库中的客户上传了持有的凭证,那么我可以将CustomerID设置为null。这没关系,除非那个客户想要访问网站,然后我们上传他的详细信息,我们就必须更新HeldVouchers表。这将导致大量的额外工作,以及大量的额外上传。
任何人都知道如何处理这个问题?我到目前为止唯一的想法是使网络数据库完全不是非关系的(我真的不喜欢这样做),然后将扩展方法添加到模拟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.NavColl<HeldVoucher>(ca => ca.CharityID == charity.ID)
第一个缺点是,我可以看到允许将Func传递给扩展方法而没有让Linq-To-Entities抛出异化的唯一方法是在应用之前枚举DbSet FUNC。如果那里有大量数据,这可能会显着减慢查询速度。
也许更严重(因为我不认为性能是一个主要问题)是扩展方法需要一个可以工作的上下文。目前,我将实体放在与EF模型不同的项目中,因为这允许我从解决方案中的任何项目引用实体,而这些项目不需要引用模型的项目。这有助于保持层分离,并允许测试等。
但是,如果扩展方法需要上下文,则实体项目需要对模型项目的引用,这会引起循环引用(因为模型需要知道实体)。我不能将扩展方法放在模型项目中,因为那时我必须从每个想要使用实体的项目中引用它,这会破坏将实体拆分成自己的项目的全部目的。
任何想法?对不起,这是一个很长的问题,但我想确保我清楚地解释了这个问题。
答案 0 :(得分:2)
我们遇到的第一个问题是术语。缺少外键的数据库不是非关系型的。它仍然是一个关系数据库,它只是没有DRI(声明性参照完整性)。
我认为在数据可能丢失的情况下,您必须设计没有外键的数据库。这不会阻止您在EF中定义这些实体之间的关系。我们一直这样做。您没有表明您是否正在使用EDMX或Code First。我们使用EDMX,过去我们所有的实体都映射到视图。就EF而言,我们的数据库中没有外键关系(因为视图映射)所以我们只是将它们绘制在自己中,并且我们在实体之间获得了完整的导航属性支持。