如何用C#表示MySQL数据库模式?

5
标题不太准确,但我想不出更好的了。
我正在尝试编写一个MySQL连接器,用于MS的Forefront Identity Manager(FIM基本上是一个同步引擎,它使用元目录在各种数据源之间同步身份)。但是我很难设计出一个合适的方案。
假设我想将用户数据从数据库导入到FIM的元目录中。用户对象具有各种属性,如名字、姓氏、地址等。在数据库中,这些属性可以分布在多个表中。FIM最终需要将这些属性合并为一个对象。因此,用户需要配置连接器以告诉它数据在DB中的存储方式。
我想知道表示此配置的“最佳”方法是什么。两种替代方案浮现在我的脑海中:
  1. 我可以保存一个合并/连接数据的选择查询,使结果成为带有所有所需属性的单个“表格”。但问题在于,我认为我需要对这个查询字符串进行某种解析,以创建一个fim兼容模式的架构(基本上是对象类型的名称(例如“person”)和属性列表)。这个模式需要仅通过查询字符串就能创建而不实际执行查询(如果这能简化过程,我可以执行一些虚假查询)。
  2. 我可以创建一些类来表示数据库模式,即表格和关系。由于我对MySQL(或者数据库)不是很熟悉,因此存在错过一些特殊情况的风险。另外,这可能是一种过度设计,因为一旦配置好了模式,它就可以被视为固定的。

是否有人对应该选择哪种替代方案以及如何解决相应问题有建议?或者还有其他更好的替代方案吗?任何建议都将不胜感激!如果有不清楚的地方,请告诉我。

编辑:由于有一些关于用例的问题,我会详细说明一下:

作为我已经说过的,我正在开发FIM的管理代理。 FIM提供所谓的可扩展连接管理代理,它基本上是一个实现了几个接口的单个类。(请参见this technet guide以获取示例实现)。由于我想为管理MySQL数据库中的标识开发通用代理,因此我不知道数据库布局在编译时。当最终用户想要使用管理代理时,他需要决定他想管理哪些身份的属性。因此,我需要给用户一些方法来配置管理代理。我的主要问题是如何设计类来保存这个配置。
让我们看一个简单的例子: 假设您想管理员工身份。为了简单起见,我们有三个属性:
- firstName - lastName - department
在这个例子中,它可能只是一个有4列的单个表格(属性加上一个ID)。但更好的设计是使用两个表格,一个用户表和一个部门表,使用1:1关系来定义用户所属的部门。
FIM要求我将这些属性合并到一个对象中。它提供了一个类CSEntryChange,其中包含AttributeChanges集合成员。然后我会创建一些AttributeChange实例(基本上包含属性名称和其值),并将它们添加到集合中。因此,可编辑的配置必须告诉管理代理如何从数据库中获取具有所有定义属性的用户,并且如何在该数据库中创建和修改用户。
理想情况下,我会有一个“MySQLSchema”类的实例(由用户事先配置),它可以返回一个包含数据库中所有用户的List<CSEntryChange>(为了解耦合,我实际上不会使用CSEntryChange类,但你应该明白我的意思)。此外,我希望能够传递一个CSEntryChange,这将导致相应的数据库条目被更新(如果尚未存在则创建)。希望这样能更加清楚 :)

你可以看一下这篇文章:http://stackoverflow.com/questions/17435224/mapping-c-sharp-objects-to-database-schema,或许能够帮助澄清问题。无论使用哪种数据库软件,我都会尝试 ORM 方法。 - YvesR
5个回答

2
我认为你真正的问题是:“如何通过C#访问MySQL实体?”
首先,我希望你正在构建一个MVC应用程序
我建议您在学习和实现方便性方面坚持使用完整的Microsoft堆栈。
有了这个想法,您将需要按以下步骤创建一个EntityFramework MySQL数据提供程序:
  1. 创建一个新项目并通过Nuget包管理器UI或在包管理器控制台中键入Install-Package EntityFramework -Version 6.0.2(并从Web项目中添加对此项目的引用)。在页面的中间位置查找“配置EntityFramework以与MySQL数据库一起工作”。
  2. 通过Nuget包管理器UI安装Entity Framework的MySQL提供程序,或者在包管理器控制台中键入Install-Package MySql.Data.Entity
下一步需要了解数据库配置更改,这些更改在此处有详细说明:配置EntityFramework以与MySQL数据库一起使用
您应该最终获得一个良好的类结构,它将允许您通过EF遍历实体的导航属性。
根据您的应用程序所需的安全级别,您可能还希望创建仅包含远程调用所需数据的数据传输对象(DTO),从而保持数据调用的效率。
这绝不是如何做这件事的权威指南,但希望为您提供正确方向的起点。
关于您上面提到的第一步:
“我可以保存一个合并/连接数据的选择查询,以便结果是具有所有所需属性的单个“表格”。但问题在于,我认为我必须对这个查询字符串进行某种解析,以创建一个fim兼容模式(基本上是对象类型的名称(例如“person”)和属性列表)。这个模式需要仅从查询字符串中可创建,而不实际执行查询(如果这能简化过程,我可以执行一些虚假查询)。”
我稍微有点困惑。您是说您想根据应用程序请求动态更新数据库模式吗?

抱歉回复晚了,一直没有时间。您的方法是否支持通过XML文件配置数据库模式?因为我的问题的核心是,最终用户需要使用他/她的数据库设置我的服务的数据库模式。 - Tobi
你能详细谈谈你的使用情况吗,特别是为什么要让最终用户定义数据库模式?一开始听起来不像是好的设计,但你可能有一个完全有效的理由,这是有道理的。如果是这种情况,我建议使用NoSQL数据库,其中一些在这里列出:http://nosql-database.org/和http://en.wikipedia.org/wiki/NoSQL - ElHaix
嗨,ElHaix,我已经更新了我的问题并提供了更多信息。这样清楚吗? - Tobi
对于具有不同模式的情况,我建议使用NoSQL数据库 - 可以看看Redis或ElasticSearch,两者都有各种.Net连接器。 - ElHaix
这也不是可行的选择。你必须想象一下,一个潜在客户有一个巨大的数据库,用于存储某些身份数据、用户或类似的东西。构建一个需要他重新设计或大幅更改数据库的解决方案是不可接受的。你可以假设数据库和用户端的设置是绝对固定的。我只能控制“另一边”,而我希望在满足上述约束条件的同时尽可能地灵活和用户友好。 - Tobi
显示剩余7条评论

1

0
当您使用MySQL Connector/Net时,您也可以像MSDN中的示例一样使用Entity Framework
using (var db = new BloggingContext())
{
    // Create and save a new Blog
    Console.Write("Enter a name for a new Blog: ");
    var name = Console.ReadLine();

    var blog = new Blog { Name = name };
    db.Blogs.Add(blog);
    db.SaveChanges();
}

0

我有一些使用.NET <-> MySQL通信的经验,过去我使用过Entity Framework进行通信——我遇到了很多问题和性能问题,并很快后悔使用它(这是1-2年前的事情,也许他们已经解决了)。当然,使用ORM框架会在您的数据库通信之上添加一个层,对于我来说,在性能和灵活性方面并不理想。

最后,我选择采用以下方法:

1)创建与使用Entity Framework相同的POCO类模型。这些模型可能包含关系,也可能不包含关系——取决于您的喜好。我更喜欢仅在实际需要它们时才添加关系(因此某些对象可能在POCO中具有其数据库关系,而其他对象可能没有)。我之所以选择这样做,是因为它降低了预加载关系和不预加载关系的复杂性。基本上,如果不需要它,请不要添加它。

2)创建数据访问层(例如,使用仓储模式),该层接受并处理这些对象,并直接向MySQL发出查询。这不需要EF-您只需要安装Connector/NET for MySQL即可。

一个快速的示例如下(注意:这个示例是我随意想出来的,只是为了说明类。我还会使用命令参数来防止注入等问题):
public class Person{
  public string Name {get;set;}
}

public interface IPersonRepository{
  void AddPerson(Person p);
} 

public class PersonRepository{
  public void AddPerson(Person p){
    using(var connection = new MySqlConnection("some connection string"){
      connection.Open();

      var command  = new MySqlCommand(connection);
      command.Text = string.Format("insert into Person (Name) values ({0})", p.Name)l
      command.ExecuteNonQuery();
    }

  }
}

对我来说,这种方法的好处有:

  • 性能 - 我的应用程序需要将大量数据插入MySQL。Entity Framework 无法处理这个问题。如果您的应用程序不处理大量数据,则可能可以使用EF。

  • 灵活性 - 编写自己的查询使我能够更好地控制通信。例如,您可以选择在MySQL中使用批量插入(从文件 - 当您需要处理大量数据时非常强大和快速),这将需要绕过Entity Framework。我还发现EF生成了一些奇怪的查询

当然,主要缺点是更多的工作 - 您将获得一些免费的东西与Entity Framework。

因此,我可以推荐以下内容:

  • 考虑需要处理的数据量,并使用这些数据量创建一个小型练习应用程序。EF(或任何其他ORM)如何处理它?直接查询数据库呢?这将为您提供有关通信性能的相对准确的想法。

  • 考虑您构建此应用程序的时间 - 如果您正在寻找快速解决方案并愿意牺牲一些性能,请选择EF或其他ORM框架。如果您有更多时间,并且希望制作灵活的解决方案,请选择直接查询数据库。

祝你好运!


感谢你的回答,但如果我理解正确的话,那么我必须在我的类中硬编码数据库架构。但是我问题的重点是如何实现“动态”架构,即可由XML文件进行配置。或者您是否误解了我的意思? - Tobi
@Tobi,啊,我明白了。我想我在解释你的问题时错了。这比仅仅访问与MySql数据库通信更复杂。对此感到抱歉。在这种情况下,我会创建一个映射层,在其中存储需要同步的每个属性,并将其位置存储在数据库中(这是可配置的部分,并将其存储在xml文件中)。然后,您的存储库将使用映射层获取表/列并根据这些构建查询。 - sTodorov

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接