【问题标题】:Entity Framework and Repository Pattern conceptual difficulties实体框架和存储库模式概念上的困难
【发布时间】:2017-06-16 09:53:15
【问题描述】:

我正在使用 ASP.NET MVC 和 SQL Server 2012 创建一个 Intranet 网站。我正在使用 Onion Architecture 创建一个存储库和架构。我的问题是我工作的公司已经有几个服务器数据库,其中表之间没有关系。相反,有表格来映射这些关系。例如,一个表 User 和一个表 Document 有一个表 User_joint_Document 来建立关系,包含两个 ID(IDDocument 和 IDUser)。现在,当我编写我的通用存储库时:

class Repository<T> : IRepository<T> where T : class 

问题是通用类型 T 没有意义,我无法使用正常的 EF 查询影响模型中的值,如果有一个父类 BaseEntity 来为每个表定义 ID,那就太好了,那么我可以写:

class Repository<T> : IRepository<T> where T : BaseEntity

而且我所有的表模型都将继承自 BaseEntity。但这也意味着以关系方式重写整个数据库并手动映射每个数据库 POCO(如果我错了,请纠正我),而且我没有这样做的技能(不同的服务器数据库中有 300 多个表我缺乏适当的知识和经验来做这种操作)。

有没有办法保留我原来的数据库结构,并且仍然编写一个通用存储库?怎么做呢?

编辑澄清我的问题,因为@saeb 部分回答了我的问题。我可以在没有 DB POCO 的父类的情况下拥有通用存储库吗?还是我需要它以便只有一个存储库来统治它们?例如:

class Repository<T>:IRepository<T> where T : class
{
  private readonly ApplicationContext context;
  private DbSet<T> entities;
  public Repository(PrincipalServerContext context)
  {
        this.context = context;
        entities = context.Set<T>();
  }
  public T Get(long id)
  {
     return entities.SingleOrDefault(s => s.IDUser == id);
     //This does not work, IDUser isn't recognized

  }

感谢您的帮助!

【问题讨论】:

  • 您给出的UsersDocuments 的示例在数据库中是正确的。一个用户可以拥有多个文档,因此您需要一个User_joint_Document 的联结表。这正是关系数据库的结构。
  • 但是如果你使用 Onion 架构,有一个包可以自动为你创建存储库,你只需要在 DataOnion 中注册它们。
  • @melkisadek 呸!这就是我在数据库上工作的糟糕程度。我原以为您会在两个表之间建立类似 1-1 的关系或类似的关系?也许那个 rel'ship 是一张实际的桌子?真的不是我坚强的一面。如果我用 ID 创建一个父类,那个关系表会变成什么?因为它有 IDDocument 和 IDUser,但现在我只能从父类获得 ID
  • 我假设数据库中设置了 PK/FK 关系?联结表根据您的多对多需求创建一对一关系。这只是使Many => 1 to 1
  • 是的,我正在使用他们的包并使用工作单元和存储库。您所要做的就是声明域类及其正确的 EF 配置。

标签: c# entity-framework repository-pattern onion-architecture


【解决方案1】:

...有几个服务器数据库,其中表之间没有关系...

但是他们确实有一个关系,Many-to-Many 关系,它是通过第三个映射表定义的(这是否是一个正确定义的关系是另一个话题)

...问题是通用类型 T 没有意义,我无法使用 EF 查询影响模型中的值...

为什么不能,为什么你不能?考虑到您的表格示例,您将有两个实体,UserDocument,它们看起来像这样:

public class User
{
    public int IDUser { get; set; }

    public virtual ICollection<Document> Documents { get; set; }

    ...
}

public class Document
{
    public int IDDocument { get; set; }

    public virtual ICollection<User> Users { get; set; }

    ...
}

您可以在上下文的OnModelCreating 中使用流利的 API 通过第三个表设置关系:

public class YourContext: DbContext
{
    ...

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
            .HasMany<Document>(u => u.Documents)
            .WithMany(d => d.Users)
            .Map(userJointDocument =>
                {
                    userJointDocument.MapLeftKey("IDUser");
                    userJointDocument.MapRightKey("IDDocument");
                    userJointDocument.ToTable("User_joint_Document");
                });
    }

    ...
}

然后您可以在存储库中查询Users 和Documents,就像它们之间存在直接关系一样。 Heremoresources 如果您愿意,可以了解更多信息。

【讨论】:

  • 感谢您提供准确的答案和良好的文档。我已经这样做了,但我的回购仍然遇到问题,我无法识别 ID。我已经编辑了我的问题以显示我的 repo 的样子
  • 不能奇怪地标记你
【解决方案2】:

据我所知,现在有一种方法可以实现这一目标,而无需至少为您的实体/POCO 放置一个基类或接口

您可以使用表达式来实现通用存储库

public interface IEntity<T> where T : class
{
    Expression<Func<T, bool>> GetByIdPredicate(long id);
}        

public partial class User : IEntity<User>
{
   public int UserID { get; set; }

   public Expression<Func<User, bool>> GetByIdPredicate(long id)
   {
      return (User entity) => entity.UserID == id;
   }
}

class Repository<T>:IRepository<T> where T : class, IEntity, new()
{
  private readonly ApplicationContext context;
  private DbSet<T> entities;
  T dummyEntity;

  public Repository(PrincipalServerContext context)
  {
        this.context = context;
        entities = context.Set<T>();
        dummyEntity = new T();
  }
  public T Get(long id)
  {
     return entities.SingleOrDefault(dummyEntity.GetByIdPredicate(id));
  }

可能还有一种更简洁的方法也可以摆脱 dummyEntity 字段

【讨论】:

  • 哦,这是一个非常有趣的观点。实际上,我已经重新提出了我的问题并在这里得到了另一个答案,如果您有兴趣,可以使用表达式方法将其全部打包在一个方法中:stackoverflow.com/questions/44591796/…
猜你喜欢
  • 2010-12-11
  • 2010-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多