如何使用具有通用存储库模式的连接 - 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()
,它就会在数据库中 运行。请注意,您必须将相同的上下文传递给两个存储库才能使其正常工作。
我建议您也查看工作单元设计模式。它在处理多个存储库时很有帮助。
当涉及多个实体集时,这是一种更结构化且更易于维护的处理事务的方式,并促进了更好的关注点分离。
希望我正确理解了您的问题,这对您有所帮助。
我在使用 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 倍...
我有一个像下面这样的 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()
,它就会在数据库中 运行。请注意,您必须将相同的上下文传递给两个存储库才能使其正常工作。
我建议您也查看工作单元设计模式。它在处理多个存储库时很有帮助。
当涉及多个实体集时,这是一种更结构化且更易于维护的处理事务的方式,并促进了更好的关注点分离。
希望我正确理解了您的问题,这对您有所帮助。
我在使用 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 倍...