复杂(多模式)实体框架对象映射,用于办公管理应用程序的无缝集成(和最终替换)

时间:2013-11-09 20:18:46

标签: c# sql entity-framework domain-driven-design foxpro

我是一个相当新手,爱好者的程序员。这是我的第一个问题,但我现在已经使用stackoverflow获取有价值的信息几个月了。

首先,一些背景:

我目前在一个非常小的(< 10名员工)专科医生的办公室工作,让我处于一个独特的位置,我有自由的统治(和适度的资源支持)到开发和实施任何类型的应用程序/工具,没有任何需求或压力,因为当前系统运行良好。

我们目前运行一个相当过时(约2008年)的医疗办公室管理系统,负责处理患者业务帐户,账单和保险索赔提交。办公室本身很容易联网。我们有几台使用标准DICOM的诊断机,但大多数医疗记录都是纸质的。

我的目标可能比我目前的愿望还要多,但我计划慢慢开发一个更全面,领域驱动的应用程序,将电子医疗记录(评估/管理和DICOM诊断)与医疗办公室管理结束。一旦我有这样一个应用程序的框架,我的情况的沙箱方面吸引我,我可以探索和开发任何我能梦想的自动化或工具。

有些诚实:

我的经历在这些方面非常有限,但我是一个非常坚定的人,我喜欢应用驱动的学习。

我的问题:

我正在努力首先整合当前的患者账户数据库。

目前所有内容都存储在FoxPro 2.5免费表中。表之间的关系不是隐含可获得的,但暗示了很多。理想情况下,我希望将我的新应用程序与POCO映射到EF到SQL数据库。这部分很简单,但我也希望在单独的DBContext中将相同的POCO映射到当前的FoxPro 2.5 .dbfs(它不一定具有相同的模式)。

我想象的这样的事情是否可能?我一直在测试得到所有fluentAPI映射(.ToTable().HasColumnName()等)的水域,但这是一项相当艰巨的任务,我希望在潜水之前先了解一些更有经验的见解。我一直无法找到任何有关人员拉出我正在尝试的事情的相关例子,这也有些令人沮丧。

也许我的做法是错误的。我愿意相应地进行调整,但我喜欢在我的应用程序中使用POCO的想法,并且我的新应用程序能够与旧数据库通信而不实现其不直观的架构非常重要。

所有头痛的关键目的是让当前应用程序保持完整功能,同时允许我运行和开发我的新应用程序。

简而言之:

是否可以使用EF将新的OOR /域驱动的应用程序与稍有不同的架构的旧数据库集成?如果是这样,任何提示或示例让我开始?如果没有,我还有其他功能相似的替代方案吗?感谢


编辑1:

我将从现在开始将当前使用的应用程序称为App X.

App X的前任在Unix上运行并且也在FoxPro / xBASE表上运行,因此App X建立在可能的基础之上,可能会使客户升级变得微不足道。 App X目录还包含Visual Fox Pro 6 .dll和一个带有FoxPro .ico的应用程序文件,名称为" fbaseeng"这将打开一个标题为" DTS Command Prompt"的命令提示符窗口。我不确定App X是如何选择的,但是' DTS'向我伸出手,我花了一些时间看看是否有办法可以使用他们已经实施的任何数据转换,但我最终放弃了。

当前数据库是 231 .dbf表的集合。幸运的是,其中很大一部分看起来要么完全没用,要么仅用于临时的临时方式,即他们不会在App X的运行时间之外存储记录。

其中一些表似乎是链接表,另一部分表包含类型限定符属性

等参考数据
public partial class Accttype
{
    public decimal Acct_Type { get; set; }
    public string Acct_Desc { get; set; }
    public string Sb { get; set; }
    public decimal Fee { get; set; }
    public bool Acptasgn { get; set; }
    public decimal Insclass1 { get; set; }
    public decimal Insclass2 { get; set; }
    public decimal Insclass3 { get; set; }
    public decimal Insclass4 { get; set; }
    public decimal Insclass5 { get; set; }
    public string Acct_Grp { get; set; }
}

和邮政编码等静态参考值

public partial class Zip
{
    public string Zipcode { get; set; }
    public string City { get; set; }
    public string St { get; set; }
    public string Areacode { get; set; }
    public decimal Ext_From { get; set; }
    public decimal Ext_To { get; set; }
}

到目前为止,我最关注以下表格:

- Patdemo.dbf     包含所有患者参观实践的记录。它有大约100     列和包含大量信息,包括姓名,地址,保险     类型,运行帐户余额总计等。直接主键即     患者ID,但格式为' 0.0'。

- Billing.dbf     包含与特定日期的患者相关的字母数字ID索引账单     服务。有大约80列,包括大多数外键/类型限定符和状态     指标(即INS1_SENT)。有患者ID的FK

- Charges.dbf     包含属于每个帐单的订单项。它可以是每个继承的表,也可以是     费用和过帐/付款的加入,因为它包含C或表示的两个记录     P     在“类型”列中。它似乎不是一个简单的主键,但Charges有     ChargeID和发布/付款的格式PostIDBillID+"000N"。至      抛出一个曲线球,然而,排泄调整没有ChargeID / PostID。有FK      BillID

- Insur.dbf     包含保险提供商和从地址到电子账单ID的信息。     主键是字母数字ICode(例如:BC01)。

- Patins.dbf     似乎是一个链接表,但也包含患者保险等信息     策略的ID号。拥有患者ID和ICode的FK。

我想要保持并发的各种其他参考表(如诊断,转诊医生和CPT代码),但现在它们的优先级较低。

我还没有完全设计出我的新应用程序架构,但我知道,无论是否与患者或保险有关,地址等事情都将是一个具体类型更合乎逻辑公司

为了这个例子,让我们看一下预先存在的Patins.dbf POCO(它是最小的表之一):

public partial class Patins
{
    public decimal Custid { get; set; }
    public decimal Inskey { get; set; }
    public string Insurcode { get; set; }
    public string Insurnum { get; set; }
    public string Groupnum { get; set; }
    public string Guarlname { get; set; }
    public string Guarfname { get; set; }
    public string Guarmi { get; set; }
    public string Guargen { get; set; }
    public string Guaraddr { get; set; }
    public string Guaraddr2 { get; set; }
    public string Guarcity { get; set; }
    public string Guarst { get; set; }
    public string Guarzip { get; set; }
    public string Guarcountr { get; set; }
    public string Guarphone { get; set; }
    public string Guaremail { get; set; }
    public System.DateTime Guardob { get; set; }
    public string Guarsex { get; set; }
    public string Guaremp { get; set; }
    public decimal Relation { get; set; }
    public System.DateTime Startdate { get; set; }
    public System.DateTime Enddate { get; set; }
    public bool Active { get; set; }
    public string Bcpc { get; set; }
    public string Auth1 { get; set; }
    public string Auth2 { get; set; }
    public string Auth3 { get; set; }
    public decimal Billcnt { get; set; }
    public string Desc1 { get; set; }
    public string Desc2 { get; set; }
    public string Desc3 { get; set; }
    public decimal Visits1 { get; set; }
    public decimal Visits2 { get; set; }
    public decimal Visits3 { get; set; }
    public System.DateTime From1 { get; set; }
    public System.DateTime From2 { get; set; }
    public System.DateTime From3 { get; set; }
    public System.DateTime To1 { get; set; }
    public System.DateTime To2 { get; set; }
    public System.DateTime To3 { get; set; }
    public string Insnote { get; set; }
    public string Char1 { get; set; }
    public string Char2 { get; set; }
    public string Char3 { get; set; }
    public string Char4 { get; set; }
    public string Char5 { get; set; }
    public string Char6 { get; set; }
    public string Char7 { get; set; }
    public string Char8 { get; set; }
    public string Char9 { get; set; }
    public string Char10 { get; set; }
    public System.DateTime Date1 { get; set; }
    public System.DateTime Date2 { get; set; }
    public decimal Num1 { get; set; }
    public decimal Num2 { get; set; }
    public string Createby { get; set; }
    public System.DateTime Createdt { get; set; }
    public string Modifyby { get; set; }
    public System.DateTime Modifydt { get; set; }
    public string Cobmemo { get; set; }
    public System.DateTime Dinju { get; set; }
    public System.DateTime Dsimbd { get; set; }
    public System.DateTime Dsimed { get; set; }
    public string Createtm { get; set; }
    public string Modifytm { get; set; }
    public bool Archive { get; set; }
    public bool Delflag { get; set; }
    public decimal Coinsded { get; set; }
    public decimal Outpoc { get; set; }
    public System.DateTime Lastupd { get; set; }
    public decimal Coins { get; set; }
    public decimal Msp { get; set; }
}

在现实世界中,患者通过保险单与保险公司联系。有FK_PatientIDFK_InsuranceCarrierID和唯一ID PK_PolicyNumber(可能是PolicyNumber + InsuranceCarrierID是安全的吗?)。政策有利益信息决定支付,配偶/家庭可以分享政策(通常在政策号码上附加-0n)。

我可能会让Patient个对象包含一组保险单对象。沿着这些方向:

class Patient : Person
{
    int PatientID { get; set; }
    virtual IEnumerable<InsurancePolicy> InsurancePolicies { get; set; }
}

class InsurancePolicy
{
    int PatientID { get; set; }
    string PolicyNumber { get; set; }
    string GroupNumber { get; set; }
    bool IsActive { get; set; }
    DateTime startDate { get; set; }
    DateTime endDate { get; set; }
    int InsuranceCarrierID { get; set; }
    virtual Person Guarantor { get; set; } //all guarantor information accessible via person aggregate root i.e: Guarantor.FirstName
    string GuarantorRelation { get; set; }
    string[] Benefits { get; set; }  //delineated set of benefit descriptions... automatically parse from EDI benefits message?... seperate value object class?... could contain copay/deduc/OoP
    decimal Deductible { get; set; }
    decimal Copay { get; set; }
    decimal OutofPocket { get; set; }
    virtual IEnumerable<Bill> AssociatedBills { get; set; } //all bills associated with policy... could also be InsuranceClaim objects... Automapper Bill->Claim?
}

还有一些其他的事情需要在InsurancePolicy或其他地方表示,如支付率百分比,但我现在暂时离开它们。

在寻找将数据映射到旧FP表或从旧FP表映射数据的方法时,我的问题终于到了。特别关注Guarantor:作为Person对象,它将存储在SQL模式的继承表中,那么最好的映射方法是什么?只有.ToTable("Patins") InsurancePolicyMap (t => t.Guarantor.FirstName).HasColumnName("Guarfname")似乎合乎逻辑,但EF会自动处理单独的关系模式吗?措辞可能更好:导航物理Person.FirstName,SQLMap,InsurancePolicy.Guarantor.FirstName,VFPmap和物理Patins.Guarfname之间的关系/继承是否有问题?

Billcnt怎么样?幸运的是,无论出于何种原因,它都没有在App X中实现,但是我认为AssociatedBills.Count()的映射是什么?您是否只需检查从FP表中提取值的有效性?

1 个答案:

答案 0 :(得分:0)

由于你有“自由统治”,我会抓住机会升级整个系统。这是一个非常糟糕的数据模型,在任何时候拖延这个遗产都没用。这些不起眼的重复编号字段将是混乱和错误的连续来源。从它建立一个体面的领域几乎是不可能的。实体框架有很多选项可以不同于数据模型来塑造类模型,但这样做太多了。实际上,在保持数据模型的同时重建应用程序是没用的。

您绝对应该规范化数据模型。使用Insclass的外键创建Accttype之类的表,依此类推。也是一个Benefit表,其FK为InsurancePolicy,因为您无法将字符串数组映射到数据库列。

但首先(并且最重要的是)明确要求。拥有完全自由来构建“任何类型的应用程序”听起来不错,但用户总是想到一些东西。在你输入一行代码之前,我会花很多时间去挑选他们的大脑。首先同意要做的事情。然后在用例之后开始构建应用程序用例。让他们测试每个用例。这将使他们有时间适应新系统并慢慢脱离旧系统,并随时调整需求。 (简而言之,这就是敏捷开发)。