gpt4 book ai didi

entity-framework - 首先使用MEF插件和EF代码-怎么做?

转载 作者:行者123 更新时间:2023-12-03 13:55:20 27 4
gpt4 key购买 nike

背景:
我们有一个包含许多模块的项目。我们正在使用带有FluentAPI(CodeFirst)的EntityFramework 4.2。

有一个名为Diverto.ORM.EntityFramework.SQLServer的中央项目,该项目包含使用FluentAPI构建上下文的部分类(并具有对解决方案上所有其他项目的引用)。
最近,我们收到了客户的要求,以实现许多其他功能,而该解决方案将需要其他几个项目。其中一些项目将来自另一个系统(人力资源),并且将创建一些项目。现有解决方案的核心是财务系统。

我们想使用MEF即时启用和禁用这些新项目(以及GUI,业务逻辑和所有)。它们将作为插件进行交互,并且也将使用MEF填充应用程序的主菜单。
但是,由于它们必须共享数据,我们对于如何启用/禁用这些模块/项目(新模块和HR模块)并没有真正的线索。

考虑一下:
-具有DbSet 和DbSet 的DivertoContext(主上下文)。
-具有DbSet 的PluginContext(来自插件)。

现在,考虑到在GUI中,我必须有权访问ClassA,ClassB和ClassC中的数据(如果有插件)。

找到解决方案!见波纹管

嘿,您在这里,请在回答之前阅读本说明!

我注意到有些人将其签出并将其标记为收藏或赞誉。请记住,这个答案可以追溯到2012年,从那以后EntityFramework发生了很大变化。

另外,请记住,每个项目都有其自己的需求。那时,我需要这种功能。您的项目可能根本不需要此功能,或者仅需要其中一部分!

最后,只是为了确保所有内容都被掩盖,是的,可以使用EF 6.1和EF迁移进行此工作,并且使用其他ORM和迁移框架也可以进行此工作。

您可能需要其他一些接口,以作为要加载的迁移的接口,并正确处理特定的插件迁移(不要将其与其他插件混合使用,因此请尝试为每个插件实现某种唯一的令牌)。

最佳答案

找到解决方案!

好吧,我将在这里尝试解释,因为在其他地方找不到。对于那些必须创建一个将接收多个插件的基本软件的人们来说,这很有趣,这些插件必须与单个数据库中的现有数据进行交互。

首先,我将使用带有CodeFirst API等的Entity Framework。因此,如果您要研究此内容,我建议您阅读MSDN中的EntityTypeConfiguration和MSDN中的Code First Fluent API

现在,让我们强调一些事情:


您必须只有一个上下文,一切才能正常工作。我将深入探讨该问题,并展示一种在应用程序的上下文中具有来自插件的类的方法,但是要使其正常工作,您必须了解通用存储库模式。我在这里只显示一点,但建议您继续研究,并尝试为您的应用创建最佳界面。
MEF将在这里成为我们的朋友。我认为您已经知道如何使用MEF创建简单的插件以及如何访问该插件中的方法。另外,我将尽量避免深入研究MEF,因为这里不是这种情况,因为您可以使用其他解决方案。实际上,我之所以使用MEF,只是因为我已经对它有所了解。
如果您要进入“哦,我需要处理多个上下文创建,这些上下文将指向一个数据库以及所有数据库”,那么您做错了。这一切都与简单的配置和一些流畅的API有关。相信我:我已经在互联网上搜索了一个星期,最后与一位朋友交谈后,我们找到了这种解决方案,这真的很简单=)。



第一件事

解决方案:MEFTest
项目:


Base.ORM(将保存ORM的接口)
Base.ORM.EntityFramework.SQLServer(将保存EF的基类)
SampleApplication.ORM.EntityFramework.SQLServer(将保存应用程序的上下文)
SampleApplication(可执行)
MEFPlugin(将容纳我们的插件)


现在,编码

在Base.ORM项目中,使用您认为合适的方法创建通用存储库接口,但未键入该接口。它将类似于:

public interface IRepository
{
bool Add<T>(T item);
}


从现在开始,我将其称为IRepository以使事情保持简单。
我将考虑一种称为Add(T item)的方法来进行示例编码。

在Base.ORM.EntityFramework.SQLServer内部创建一个BaseContext类,该类继承自DbContext并且实现IRepository。它看起来应该像这样:

public class BaseContext : IRepository
{
public bool Add<T>(T item)
{
try { Set<T>().Add(item); return true; }
catch { return false; }
}
}


您可以在此处添加自定义IDatabaseInitializer基本实现,以进行数据库版本控制。我已经使用标准文件夹中的SQL文件完成了此操作,但这是旧的编码,因为EF现在支持迁移。

如果您仍要手动处理此问题,请记住在此之前将数据库设置为单用户模式,然后再将其还原为多用户模式。请记住:try ... catch ... finally将在这里有所帮助,因为您可以在finally中还原为多用户,因此即使出现错误也不会留下任何问题。

在SampleApplication项目中,添加:
ClassA(整数ID,字符串名称)和ClassB(整数ID,DateTime TestDate)。

在SampleApplication.ORM.EntityFramework.SQLServer内部,创建您的标准上下文。
我将在这里使用三个具有非常有趣名称的类:ClassA,ClassB和ClassC。
这个项目同时引用了ClassA和ClassB,它将是这样的:

public class Context : BaseContext
{
public DbSet<ClassA> ClassA { get; set; }
public DbSet<ClassB> ClassB { get; set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
/* I'll talk about this later. Just override the OnModelCreating and leave it */
base.OnModelCreating(modelBuilder);
}
}


现在有趣的部分:插件将具有以下方法:

public void Setup(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ClassC>().ToTable("ClassC");
modelBuilder.Entity<ClassC>().HasKey(_classC => _classC.Id);
modelBuilder.Entity<ClassC>().Property(_classC => _classC.Date2).HasColumnType("datetime2").HasPrecision(7);
}


当然,ClassC在插件​​项目内部。您在主项目中没有任何引用。
您将必须使用MEF和接口(当然是接口)来找到此方法(安装程序)。我将展示在何处放置它以及如何使其工作=)

回到Context类,OnModelCreating方法将如下所示:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ClassA>().ToTable("ClassA");
modelBuilder.Entity<ClassA>().HasKey(_classA => _classA.Id);

modelBuilder.Entity<ClassB>().ToTable("ClassB");
modelBuilder.Entity<ClassB>().HasKey(_classB => _classB.Id);
modelBuilder.Entity<ClassB>().Property(_classB => _classB.TestDate).HasColumnType("datetime2").HasPrecision(7);

/* Use MEF to load all plugins. I'll use the mock interface IPlugin */
foreach (IPlugin plugin in MefLoadedPlugins)
plugin.Setup(modelBuilder);
}


用法

在您的APP内,您只有一个上下文。此上下文继承自实现IRepository的BaseContext。考虑到这一点,您需要对GUI和业务层进行编码,以使用IRepository(来自Base.ORM)和特定的类(特定于业务的dll)。

有用!

好吧,它在这里工作。

我想我已经在这里展示了每个相关的部分。
当然,类中还有更多代码,但事实并非如此。我试图仅显示您真正需要创建/实现的功能。

不要忘记:


不要忘记,您将不得不编写自己的代码来播种数据库。对于我这里的情况,在插件的相同接口内,我有类似Seed(IRepository)之类的东西,我在那里处理所有事情。
不要忘记您没有从主项目到插件的引用。这意味着您必须找到一种通过界面和提供程序加载菜单,GUI,业务和数据的方法。我设法使用IPlugin(业务),IFormPlugin(GUI-Winforms)和IPluginRepository(数据)来解决该问题。您将必须找到适合自己需求的名称和方法,但这应该是一个很好的起点。
不要忘记,如果加载插件,则必须在数据库内部创建表,否则EF CodeFirst将无法初始化。请记住,您可能需要SQL文件并根据需要手动运行它们以创建表。
不要忘记,如果您卸载插件,则也必须删除表,否则EF也将失败。
别忘了您确实需要备份。我还没有这样做,但是我已经标记了将在哪里完成(在DDL命令之前和之后)。
这是针对我的情况的我的解决方案。对于新项目而言,这应该是一个好的开始,但仅此而已。不要以为通过遵循我在这里所做的事情,它对每种情况都可以100%起作用。


谢谢

感谢来自SO和MSDN的人员,他们为我提供的评论和其他帖子提供了很多帮助。
感谢Caio Garcia(BR)帮助我提供了有关其他基于插件的系统的一些说明。

样本代码(完整)

以下是一些示例代码:

对于基本项目(解决方案预定义项目)

public class ClassA
{
public int Id { get; set; }
public string Name { get; set; }
}

public class ClassB
{
public int Id { get; set; }
public string OtherName { get; set; }
}

public interface IRepository
{
bool Add<T>(T item);
bool Save();
}

public class BaseContext : DbContext, IRepository
{
public bool Add<T>(T item)
{
try { Set<T>().Add(item); return true; } catch { return false; }
}
public bool Save()
{
try { SaveChanges(); return true; } catch { return false; }
}
}

public class Context : BaseContext
{
// Fill this list using MEF - check for the IPluginContext interface on assemblies
public List<IPluginContext> MefLoadedPlugins;

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ClassA>().ToTable("TableB", "Schema_1");
modelBuilder.Entity<ClassA>().HasKey(_a => _a.Id);

modelBuilder.Entity<ClassB>().ToTable("TableB", "Schema_1");
modelBuilder.Entity<ClassB>().HasKey(_b => _b.Id);

if (MefLoadedPlugins != null)
foreach (var pluginContext in MefLoadedPlugins)
pluginContext.Setup(modelBuilder);
}
}


对于插件

public class ClassC
{
public int Id { get; set; }
public string Description { get; set; }
}

public interface IPluginContext
{
void Setup(DbModelBuilder modelBuilder);
}

public class Just_A_Sample_Plugin_Context : IPluginContext
{
public void Setup(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ClassC>().ToTable("TableC", "Schema_2");
modelBuilder.Entity<ClassC>().HasKey(_c => _c.Id);
}
}


在您的常规代码上

public void DoSomething(IRepository repo)
{
var classA = new ClassA() { Name = "First Name" };
repo.Add(classA);
repo.Save();
}

关于entity-framework - 首先使用MEF插件和EF代码-怎么做?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8730830/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com