Web API 和 Entity Framework 具有一对多对多的关系
Web API and Entity Framework with a 1 to many to many relationship
我需要有关如何从一对多获取数据的帮助。我正在使用 .NET Core 3.1 Web API 和 Entity Framework.
Table 1 : 用户
ID Guid
UserName String
Table 2 : UsererAgency
UserId GUID
AgencyCode String
Table 3 机构
AgencyCode string
AgencyName String
路径是从 table User
,列 ID
到 UserAgency.UserID
和从 UserAgency
到 Agency
使用 AgencyCode
列。
我想获取所有用户及其代理机构。所以我想 return 只是:
- 来自用户的 ID
- 机构代码和机构名称 table。
这是我用来从 entity framework 获取数据的 POCO。
用户
public User()
{
public User()
{
UserAgency = new HashSet<UserAgency>();
}
[NotMapped]
public GUID ID { get; set; }
[NotMapped]
public virtual ICollection<UserAgency> UserAgency { get; set; }
}
public class UserAgency
{
[Key]
public Guid UserId { get; set; }
[Key]
[ForeignKey("Agency")]
public string AgencyCode { get; set; }
[NotMapped]
public virtual Agency Agency { get; set; }
[NotMapped]
public virtual User User { get; set; }
}
public partial class Agency
{
public Agency()
{
Employee = new HashSet<Employee>();
UserAgency = new HashSet<UserAgency>();
User = new HashSet<ApplicationUser>();
}
public string AgencyCode { get; set; }
publicstring AgencyName { get; set; }
[NotMapped]
public virtual ICollection<UserAgency> UserAgency { get; set; }
[NotMapped]
public virtual ICollection<User> User { get; set; }
}
var members = await _unitOfWork.UserRepository.FindAllAsync(null, null, new List<string> {"UserAgency" });
它正在 return 正确地处理我的数据。返回我的所有用户(这是正确的)和所有 UserAgency 以及他们在 Useragency 下的所有 Agency。我想我不知道如何向下钻取或如何格式化我的 DTO。我会使用 AutoMapper 还是可以 select 我需要什么?
有了EntityFramework,你可以这样试试:
_unitOfWork.UserRepository.FindAllAsync().Include(i => i.UserAgency).ThenInclude(i => i.Agency).Select(i => new { i.ID, i.UserAgency.Agency.AgencyCode, i.UserAgency.Agency.AgencyName
});
EF Core 中没有 _unitOfWork
、UserRepository
或 FindAllAsync
。看起来您使用了“通用存储库”anti模式,该模式通常会破坏 EF 操作,禁用真正的 UoW 功能和 LINQ 查询。 Gunnar Peipman 的 No need for repositories and unit of work with Entity Framework Core 详细解释了为什么这是个坏主意。
DbContext 已经是一个多实体工作单元。 DbSet 已经是一个单一实体的 Repository。 EF Core 中不需要“通用存储库”,因为 EF 已经提供了更高级别的抽象。但是, 有意义的是特定 存储库,这些存储库解决了特定使用 cases/scenarios/bounded 上下文(如果您更喜欢 DDD 术语)。
在 EF Core 中,return 您只需要代理 ID 和代理商数据:
var query=from user in dbContext.Users
from ua in user.UserAgency
select new {
UseID = user.ID,
AgencyCode = ua.Agency.AgencyCode,
AgencyName = ua.Agency.AgencyName };
var results=await query.ToListAsync();
匿名类型不能用作 return 类型。您可以 return 元组代替,但更简洁的解决方案是定义 record
并使用您想要的字段:
public record AgencyWithUser(Guid UserID,string AgencyCode,string AgencyName);
....
var query=from user in dbContext.Users
from ua in user.UserAgency
select new AgencyWithUser(
user.ID,
ua.Agency.AgencyCode,
ua.Agency.AgencyName);
var results=await query.ToListAsync();
如果这是一个常见的操作,代码可以作为一个函数添加到您的 DbContext。这可能是一个好主意,即使调用不那么常见,也可以从更高级别的代码中隐藏查询:
public class MyAgenciesContext: DbContext
{
....
public async Task<List<AgencyWithUser>> GetAgenciesWithUsersAsync()
{
var query=from user in this.Users
from ua in user.UserAgency
select new AgencyWithUser(
user.ID,
ua.Agency.AgencyCode,
ua.Agency.AgencyName);
var results=await query.ToListAsync();
}
}
您还可以使用满足特定用例要求的方法创建一个专业化 存储库。此查询不会有任何不同:
public MyAgencyManagementRepository
{
readonly MyContext _dbContext;
public MyAgencyManagementRepository(MyContext dbContext)
{
_dbContext=dbContext;
}
public async Task<List<AgencyWithUser>> GetAgenciesWithUsersAsync()
{
var query=from user in _dbContext.Users
from ua in user.UserAgency
select new AgencyWithUser(
user.ID,
ua.Agency.AgencyCode,
ua.Agency.AgencyName);
var results=await query.ToListAsync();
}
public async Task<List<AgencyWithUser>> GetAgenciesForUserAsync(Guid userId)
{
var query=from user in _dbContext.Users
where user.Id == useId
from ua in user.UserAgency
select new AgencyWithUser(
user.ID,
ua.Agency.AgencyCode,
ua.Agency.AgencyName);
var results=await query.ToListAsync();
}
}
与将方法放入 DbContext 没有什么不同。存储库的 真正 好处来自封装特定场景所需的复杂操作。
例如:
对于报告,您只需要查询函数,通常结合多个实体、聚合、复杂过滤。不需要事务、验证或并发管理。不过可能需要动态过滤。
对于机构管理,您需要基本的 CRUD 操作,这些操作还可以处理到用户的映射。需要 验证,您的代码将 处理并发问题。
尽管这两种情况都可以使用相同的 DbContext,但它们有不同的需求,需要不同的代码并因不同的原因而更改。他们需要不同的单元测试,甚至可能由不同的开发人员开发。
在这种情况下,创建两个单独的专业化存储库是有意义的
我需要有关如何从一对多获取数据的帮助。我正在使用 .NET Core 3.1 Web API 和 Entity Framework.
Table 1 : 用户
ID Guid
UserName String
Table 2 : UsererAgency
UserId GUID
AgencyCode String
Table 3 机构
AgencyCode string
AgencyName String
路径是从 table User
,列 ID
到 UserAgency.UserID
和从 UserAgency
到 Agency
使用 AgencyCode
列。
我想获取所有用户及其代理机构。所以我想 return 只是:
- 来自用户的 ID
- 机构代码和机构名称 table。
这是我用来从 entity framework 获取数据的 POCO。
用户
public User()
{
public User()
{
UserAgency = new HashSet<UserAgency>();
}
[NotMapped]
public GUID ID { get; set; }
[NotMapped]
public virtual ICollection<UserAgency> UserAgency { get; set; }
}
public class UserAgency
{
[Key]
public Guid UserId { get; set; }
[Key]
[ForeignKey("Agency")]
public string AgencyCode { get; set; }
[NotMapped]
public virtual Agency Agency { get; set; }
[NotMapped]
public virtual User User { get; set; }
}
public partial class Agency
{
public Agency()
{
Employee = new HashSet<Employee>();
UserAgency = new HashSet<UserAgency>();
User = new HashSet<ApplicationUser>();
}
public string AgencyCode { get; set; }
publicstring AgencyName { get; set; }
[NotMapped]
public virtual ICollection<UserAgency> UserAgency { get; set; }
[NotMapped]
public virtual ICollection<User> User { get; set; }
}
var members = await _unitOfWork.UserRepository.FindAllAsync(null, null, new List<string> {"UserAgency" });
它正在 return 正确地处理我的数据。返回我的所有用户(这是正确的)和所有 UserAgency 以及他们在 Useragency 下的所有 Agency。我想我不知道如何向下钻取或如何格式化我的 DTO。我会使用 AutoMapper 还是可以 select 我需要什么?
有了EntityFramework,你可以这样试试:
_unitOfWork.UserRepository.FindAllAsync().Include(i => i.UserAgency).ThenInclude(i => i.Agency).Select(i => new { i.ID, i.UserAgency.Agency.AgencyCode, i.UserAgency.Agency.AgencyName
});
EF Core 中没有 _unitOfWork
、UserRepository
或 FindAllAsync
。看起来您使用了“通用存储库”anti模式,该模式通常会破坏 EF 操作,禁用真正的 UoW 功能和 LINQ 查询。 Gunnar Peipman 的 No need for repositories and unit of work with Entity Framework Core 详细解释了为什么这是个坏主意。
DbContext 已经是一个多实体工作单元。 DbSet 已经是一个单一实体的 Repository。 EF Core 中不需要“通用存储库”,因为 EF 已经提供了更高级别的抽象。但是, 有意义的是特定 存储库,这些存储库解决了特定使用 cases/scenarios/bounded 上下文(如果您更喜欢 DDD 术语)。
在 EF Core 中,return 您只需要代理 ID 和代理商数据:
var query=from user in dbContext.Users
from ua in user.UserAgency
select new {
UseID = user.ID,
AgencyCode = ua.Agency.AgencyCode,
AgencyName = ua.Agency.AgencyName };
var results=await query.ToListAsync();
匿名类型不能用作 return 类型。您可以 return 元组代替,但更简洁的解决方案是定义 record
并使用您想要的字段:
public record AgencyWithUser(Guid UserID,string AgencyCode,string AgencyName);
....
var query=from user in dbContext.Users
from ua in user.UserAgency
select new AgencyWithUser(
user.ID,
ua.Agency.AgencyCode,
ua.Agency.AgencyName);
var results=await query.ToListAsync();
如果这是一个常见的操作,代码可以作为一个函数添加到您的 DbContext。这可能是一个好主意,即使调用不那么常见,也可以从更高级别的代码中隐藏查询:
public class MyAgenciesContext: DbContext
{
....
public async Task<List<AgencyWithUser>> GetAgenciesWithUsersAsync()
{
var query=from user in this.Users
from ua in user.UserAgency
select new AgencyWithUser(
user.ID,
ua.Agency.AgencyCode,
ua.Agency.AgencyName);
var results=await query.ToListAsync();
}
}
您还可以使用满足特定用例要求的方法创建一个专业化 存储库。此查询不会有任何不同:
public MyAgencyManagementRepository
{
readonly MyContext _dbContext;
public MyAgencyManagementRepository(MyContext dbContext)
{
_dbContext=dbContext;
}
public async Task<List<AgencyWithUser>> GetAgenciesWithUsersAsync()
{
var query=from user in _dbContext.Users
from ua in user.UserAgency
select new AgencyWithUser(
user.ID,
ua.Agency.AgencyCode,
ua.Agency.AgencyName);
var results=await query.ToListAsync();
}
public async Task<List<AgencyWithUser>> GetAgenciesForUserAsync(Guid userId)
{
var query=from user in _dbContext.Users
where user.Id == useId
from ua in user.UserAgency
select new AgencyWithUser(
user.ID,
ua.Agency.AgencyCode,
ua.Agency.AgencyName);
var results=await query.ToListAsync();
}
}
与将方法放入 DbContext 没有什么不同。存储库的 真正 好处来自封装特定场景所需的复杂操作。
例如:
对于报告,您只需要查询函数,通常结合多个实体、聚合、复杂过滤。不需要事务、验证或并发管理。不过可能需要动态过滤。
对于机构管理,您需要基本的 CRUD 操作,这些操作还可以处理到用户的映射。需要 验证,您的代码将 处理并发问题。
尽管这两种情况都可以使用相同的 DbContext,但它们有不同的需求,需要不同的代码并因不同的原因而更改。他们需要不同的单元测试,甚至可能由不同的开发人员开发。
在这种情况下,创建两个单独的专业化存储库是有意义的