如何使用具有通用存储库模式的连接 - Entity Framework

How to use joins with generic repository pattern - Entity Framework

我有一个像下面这样的 Generic Repository 来处理我的 CRUD,对于单个实体来说它很容易使用,当我尝试加入我的 POCOs.[=17 时问题就开始了=]

假设我有这些 POCO,它们使用流畅的 api 映射(多对多和一对多关系):

public class Student
{
    public Student() 
    {
        this.Courses = new HashSet<Course>();
    }

    public int StudentId { get; set; }
    public string StudentName { get; set; }

    //FKs 
    public virtual Standard Standard { get; set; }
    public int StdandardRefId { get; set; }

    public virtual ICollection<Course> Courses { get; set; }
}

public class Course
{
    public Course()
    {
        this.Students = new HashSet<Student>();
    }

    public int CourseId { get; set; }
    public string CourseName { get; set; }

    public virtual ICollection<Student> Students { get; set; }
}
public class Standard
{
    public Standard()
    {
        Students = new List<Student>();
    }
    public int StandardId { get; set; }
    public string Description { get; set; }

    public virtual ICollection<Student> Students { get; set; }
}

映射:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    //Many-To-Many
    modelBuilder.Entity<Student>()
                .HasMany<Course>(s => s.Courses)
                .WithMany(c => c.Students)
                .Map(cs =>
                        {
                            cs.MapLeftKey("StudentRefId");
                            cs.MapRightKey("CourseRefId");
                            cs.ToTable("StudentCourse");
                        });
        //One-To-Many
        modelBuilder.Entity<Student>()
                .HasRequired<Standard>(s => s.Standard)
                .WithMany(s => s.Students)
                .HasForeignKey(s => s.StandardId);

}

通用存储库:

public class Repository<T> : IRepository<T>
    where T : class, IDisposable
{
    internal MyDbContext context;
    internal DbSet<T> dbSet;

    public Repository()
    {
        context = new MyDbContext();
        this.dbSet = context.Set<T>();
    }

    public bool Add(T entity)
    {
        var query = dbSet.Add(entity);

        if (query != null)
            return true;
        return false;
    }

    public bool Update(T entity)
    {
        dbSet.Attach(entity);
        var query = context.Entry(entity).State = EntityState.Modified;

        if (query == EntityState.Modified)
            return true;
        return false;
    }
    public bool Delete(T entity)
    {
        var query = dbSet.Remove(entity);

        if (query != null)
            return true;
        return false;
    }
    public bool Delete(Guid id)
    {
        var query = dbSet.Remove(dbSet.Find(id));

        if (query != null)
            return true;
        return false;
    }
    public T GetById(Guid id)
    {
        var query = dbSet.Find(id);

        if (query != null)
            return query;
        else
            return null;
    }
    public ICollection<T> GetAll()
    {
        return dbSet.AsEnumerable<T>().ToList();
    }

    public void Save()
    {
        context.SaveChanges();
    }
    public void Dispose()
    {
        if (context != null)
        {
            context.Dispose();
            context = null;
        }
    }
}

现在,如果我想将标准加入到多对多 Table 我怎么才能做到这一点?

因此,根据您的编辑,我假设您愿意加入 Students and Standards。

您要做的第一件事是更改存储库,使其不实例化上下文。您应该将其作为参数传递并存储对它的引用:

public Repository(MyDbContext myCtx)
{
    context = myCtx;
    this.dbSet = context.Set<T>();
}

您要做的第二件事是更改存储库,将 GetAll() 方法更改为 return IQueryable<T> 而不是 ICollection<T>.

然后改变GetAll()的实现:

return dbSet;

这样你只会得到一个查询,而不是所有实体的评估列表。然后您可以使用存储库的 GetAll() 方法进行连接,就像使用数据库集一样:

using (MyDbContext ctx = new MyDbContext())
{
  var studentRep = new Repository<Student>(ctx);
  var standardRep = new Repository<Standard>(ctx);
  var studentToStandard = studentRep.GetAll().Join(standardRep.GetAll(), 
                        student => student.StandardRefId,
                        standard => standard.StandardId,
                        (stud, stand) => new { Student=stud, Standard=stand }).ToList();
}

有了这个,你会在 studentToStandard 中得到一个 IQueryable<T>,一旦你调用 ToList(),它就会在数据库中 运行。请注意,您必须将相同的上下文传递给两个存储库才能使其正常工作。

我建议您也查看工作单元设计模式。它在处理多个存储库时很有帮助。

https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

当涉及多个实体集时,这是一种更结构化且更易于维护的处理事务的方式,并促进了更好的关注点分离。

希望我正确理解了您的问题,这对您有所帮助。

我在使用 Entity Framework

的地方进行了此查询
var result = (from metattachType in _dbContext.METATTACH_TYPE
                join lineItemMetattachType in _dbContext.LINE_ITEM_METATTACH_TYPE on metattachType.ID equals lineItemMetattachType.METATTACH_TYPE_ID
                where (lineItemMetattachType.LINE_ITEM_ID == lineItemId && lineItemMetattachType.IS_DELETED == false
                && metattachType.IS_DELETED == false)
                select new MetattachTypeDto()
                {
                    Id = metattachType.ID,
                    Name = metattachType.NAME
                }).ToList();

并将其更改为我使用存储库模式的地方 林克

            return await _attachmentTypeRepository.GetAll().Where(x => !x.IsDeleted)
                .Join(_lineItemAttachmentTypeRepository.GetAll().Where(x => x.LineItemId == lineItemId && !x.IsDeleted),
                attachmentType => attachmentType.Id,
                lineItemAttachmentType => lineItemAttachmentType.MetattachTypeId,
                (attachmentType, lineItemAttachmentType) => new AttachmentTypeDto
                {
                    Id = attachmentType.Id,
                    Name = attachmentType.Name
                }).ToListAsync().ConfigureAwait(false);

Linq-to-sql

            return (from attachmentType in _attachmentTypeRepository.GetAll()
                    join lineItemAttachmentType in _lineItemAttachmentTypeRepository.GetAll() on attachmentType.Id equals lineItemAttachmentType.MetattachTypeId
                    where (lineItemAttachmentType.LineItemId == lineItemId && !lineItemAttachmentType.IsDeleted && !attachmentType.IsDeleted)
                    select new AttachmentTypeDto()
                    {
                        Id = attachmentType.Id,
                        Name = attachmentType.Name
                    }).ToList();

此外,请注意 Linq-to-Sql 比 Linq 快 14 倍...