【问题标题】:How to architect Entity Framework Application (with MEF)如何构建实体框架应用程序(使用 MEF)
【发布时间】:2013-01-11 03:05:34
【问题描述】:

我很想知道如何构建我的 Entity Framework 4(代码优先)应用程序。

我有一个 VS 项目来处理对我的数据的访问。它是基于接口[IDataExport] 的MEF 导出部件[MyData]。该项目有我的 EF 类(客户、订单等)、上下文初始化程序等,所有这些都已经像梦一样工作了。

我有一个 VS 项目,它有我的接口(我的所有接口)。所有项目都引用了这个接口项目。

我有一个 VS 项目来完成我的所有日​​志记录。它也是基于接口[ILogging] 的MEF 导出部件[MyLog]。该类实际上只是写入控制台。

我有三个 VS 项目,我们称之为 Parts(以 MEF 术语)。它们是插件。他们需要数据才能工作(客户、订单等)。实际上,他们需要同时从三个不同的表中输入数据。

我有一个项目是主机应用程序。它目前作为控制台应用程序运行,但很快将转换为 Windows 服务。

我希望这能让您对现有架构有一个很好的了解。现在我在试图弄清楚如何正确访问我的数据时遇到了麻烦。

当主机需要数据传递给插件时,它需要从 3 个不同的表中获取数据。实际上,使用 EF 设置的方式,将一次检索三个表。当插件由 MEF 实例化时,如何将该数据传递给插件?插件可以引发事件以与主机应用程序交互吗?

此外,随着插件的运行,表中的数据将需要更新。如何保持数据库中的数据更新三层? Host可以调用Plug-In,但是Plugin没有办法调用Host。只有[MyData] 项目可以访问数据库。

根据我描述的场景,有人可以告诉我如何最好地构建这个应用程序吗?

让我更加困惑的是,一些示例代码显示了调用应用程序(在本例中为主机),为每次对数据库的搜索调用启动全新的模型。例如

public List<Customer> FindCustomerList(string companyName)
{
    return new CustomerManager().FindCustomerList(companyName);
}


public List<Customer> FindCustomerList(string companyName)
{
    var q = from c in context.Customers
            where c.CompanyName.StartsWith(companyName)
            select c;
    return q.ToList();
}

下面是我的三张桌子。请注意,它们具有外键关系,导致子项嵌入到主作业记录中。就像一个有很多订单的客户。

public class pcJobAction : IVersionTracking, IpcIdentity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public long Id { get; set; }

    //IpcIdentity
    [Required]
    [MaxLength(75)] 
    public string name { get; set; }
    [MaxLength(1000)] 
    public string description { get; set; }
    [Required]
    [MaxLength(30)] 
    public string ServerName { get; set; }
    [MaxLength(20)] 
    public string ServerIP { get; set; }        
    public int JobEnabled { get; set; }

    public virtual ICollection<pcPlugInValue> PlugInText { get; set; }

    //JobActions holds a list of Schedules
    public virtual ICollection<pcJobSchedule> JobSchedules { get; set; }

    //FK to the JobTypes table (Delete Files, Verify Backups, Ping, etc)
    public long pcJobTypeId { get; set; }
    public virtual pcJobType pcJobType { get; set; }

    //IVersionTracking
    public DateTime DateCreated { get; set; }
    public DateTime LastUpdated { get; set; }
    [Timestamp]
    public byte[] Version { get; set; }       
}

public class pcPlugInValue : IVersionTracking, IpcIdentity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public long Id { get; set; }

    //IpcIdentity
    [Required]
    [MaxLength(75)]
    public string name { get; set; }
    [MaxLength(1000)]
    public string description { get; set; }
    public string PlugInText { get; set; }
    public int ExecuteOrder { get; set; }

    //FK to the JobAction table
    public long pcJobActionId { get; set; }
    public virtual pcJobAction pcJobAction { get; set; }

    //FK to the codes table (to indetify the schedule type: daily, weekly, etc)
    public long pcCodeId { get; set; }
    public virtual pcCode pcCode { get; set; } 

    //IVersionTracking
    public DateTime DateCreated { get; set; }
    public DateTime LastUpdated { get; set; }
    [Timestamp]
    public byte[] Version { get; set; }
}

public class pcJobSchedule : IVersionTracking, IpcIdentity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public long Id { get; set; }

    //IpcIdentity
    [Required]
    [MaxLength(75)] 
    public string name { get; set; }
    [MaxLength(1000)] 
    public string description { get; set; }

    //FK to the JobAction table
    public long pcJobActionId { get; set; }
    public virtual pcJobAction pcJobAction { get; set; }

    //FK to the codes table (to indetify the schedule type: daily, weekly, etc)
    public long pcCodeId { get; set; }
    public virtual pcCode pcCode { get; set; } 

    public DateTime StartDate { get; set; }
    public Boolean dayMonday { get; set; }
    public Boolean dayTuesday { get; set; }
    public Boolean dayWednesday { get; set; }
    public Boolean dayThursday { get; set; }
    public Boolean dayFriday { get; set; }
    public Boolean daySaturday { get; set; }
    public Boolean daySunday { get; set; }
    public Boolean ThisJobIsNext { get; set; }
    public DateTime EndDate { get; set; }
    public int DateOfMonth { get; set; }
    public int DayOfWeek { get; set; }
    public DateTime ScheduleHour { get; set; }
    public int EveryHowMany { get; set; }

    public DateTime RunTimeLast { get; set; }
    public DateTime RunTimeNext { get; set; }

    //IVersionTracking
    public DateTime DateCreated { get; set; }
    public DateTime LastUpdated { get; set; }
    [Timestamp]
    public byte[] Version { get; set; }
}

【问题讨论】:

  • 使用与 SQL 数据库相同的结构并从那里工作
  • 我不确定这是否可行。这是实体框架(一个完全不同的野兽)。我有对象,我有本地数据,我有同步,我有 ClientWins,我有 ServerWins 等等。
  • 它们在执行方面通常并不相似,但流程大致相似(以我有限的经验)。
  • 表结构现在在上面。作为对象,它们一个嵌入另一个内部。即 JobAction JobSchedule1 JobSchedule2 JobSchedule3 PluginData1 PluginData2 顺便说一句,我不明白你的评论。我知道 SQL 和表关系。我需要帮助了解什么类型的对象将保持 EF 上下文状态,可能维持多长时间,以及我是否应该为每次调用它一遍又一遍地重新创建该繁重的上下文对象。
  • 我正在为插件使用 MEF。 HOST 是一个调度程序,它调用预定的作业(基于表中的数据)。 MEF 为我提供了我想要的插件架构。本质上,如果一切都按计划进行,我可以在文件系统中添加一个新的 DLL,向表中添加一些新数据,并且 HOST 应用程序将能够在不更改代码的情况下实例化新插件。

标签: c# architecture entity-framework-4 mef


【解决方案1】:

根据您的架构描述,我可以假设您的主机应用程序在某个地方有一个 [ImportMany] 导致您的所有插件都由 MEF 实例化吗?

如果是这种情况,一种选择是(我相信您曾问过)将一个事件添加到您的插件接口并从您的主机应用程序附加到每个插件中的该事件。我自己做过,效果很好。

如果它适合您的架构,另一种选择是将您的 EF 类放在一个单独的程序集中,在您的插件程序集中引用该程序集,然后直接从插件进行数据访问。

【讨论】:

    【解决方案2】:

    我自己完成了第二个选项,我将我的 EF 代码优先类放入一个单独的程序集中,并有一些帮助类用于连接到 contextclass,并查询 ef 存储库。 但是,如果您不希望您的插件直接访问整个数据库,那么最好执行选项 1。特别是如果将来您决定将数据库表拆分为不同的模式,并且您只想要某些插件只能与数据库中的特定模式进行交互。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多