简体   繁体   English

是否可以将 DbSet 与泛型类型一起使用?

[英]Is it possible to use the DbSet with a generic type?

I've been working on a platform for a rehab center .我一直在为康复中心搭建一个平台。 We need to store the appointments info and each appointment has multiple attendance forms , each attendance form is a table in the database.我们需要存储约会信息,每个约会都有多个考勤 forms ,每个考勤表格是数据库中的一个表。 So, I have the Appointments table and one table for each attendance form.所以,我有Appointments表和每个出席表格的一个表。 I need to restore the data of a certain appointment and all the attendance forms used in that particular appointment.我需要恢复某个约会的数据以及该特定约会中使用的所有出勤 forms。 The problem is that the number of attendance forms varies for each appointment because a healthcare professional can fill different attendance forms according to the appointment .问题是每次预约的出勤人数 forms 各不相同,因为医疗保健专业人员可以根据预约填写不同的出勤人数 forms 。

The name of all attendance forms has the same prefix , so I can do this:所有考勤名称 forms 都有相同的前缀,所以我可以这样做:

var formsNamesQuery = from table in _context.GetType().GetProperties()
                      where table.Name.StartsWith("Form") 
                      select table.Name;

var formsNames = formsNamesQuery.ToList();

Doing this, now I have only the name of the attendance form tables .这样做,现在我只有出勤表的名称。 To query each table, I do this:要查询每个表,我这样做:

foreach (var formName in formsNames)
{
     var form = _context.GetType().GetProperty(formName).GetType();
     
     var formResults = _context.Set<FormType>().FromSqlRaw(
          $"SELECT * FROM {formName} WHERE PacientID = '{pacientID}' AND AppointmentID = {appointmentID}")
          .AsNoTracking()
          .FirstAsync();
}

But I don't know how to say to the DbContext the type of the form I'm searching for.但我不知道如何向DbContext说我正在搜索的表单的类型。 I've been searching a lot, but I didn't find a solution.我一直在寻找很多,但我没有找到解决方案。 I saw this question and it led me to this method :我看到了这个问题,它使我采用了这种方法

public IList RestoreFormInfo<TEntity>(TEntity entity, string formName, string pacientID, int AppointmentID) where TEntity : class
{
     var dataSet = _context.Set<TEntity>();

     var results = dataSet.FromSqlRaw(
          $"SELECT * FROM {formName} WHERE PacientID = '{pacientID}' AND AppointmentID = {appointmentID}")
          .AsNoTracking()
          .FirstAsync();
     
     return (IList) results;
}

And I call it like this:我这样称呼它:

var formResults = RestoreFormInfo(form.GetType(), formName, pacientID, appointmentID);

With this method, I can pass the form type, but I get this error :使用此方法,我可以传递表单类型,但出现此错误

InvalidOperationException: Cannot create a DbSet for 'Type' because this type is not included in the model for the context.
Microsoft.EntityFrameworkCore.Internal.InternalDbSet<TEntity>.get_EntityType()
Microsoft.EntityFrameworkCore.Internal.InternalDbSet<TEntity>.CheckState()
Microsoft.EntityFrameworkCore.Internal.InternalDbSet<TEntity>.get_EntityQueryable()
Microsoft.EntityFrameworkCore.Internal.InternalDbSet<TEntity>.System.Linq.IQueryable.get_Provider()
Microsoft.EntityFrameworkCore.RelationalQueryableExtensions.FromSqlRaw<TEntity>(DbSet<TEntity> source, string sql, object[] parameters)
SigCER.Controllers.AppointmentsController.RestoreFormInfo<TEntity>(TEntity entity, string formName, string pacientID, int appointmentID) in AppointmentsController.cs
var results = dataSet.FromSqlRaw(
SigCER.Controllers.AppointmentsController.AttendanceForms(int appointmentID, string pacientID) in AppointmentsController.cs
var formResults = RestoreFormInfo(form.GetType(), formName, pacientID, appointmentID);
lambda_method(Closure , object )
Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable+Awaiter.GetResult()
Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor+TaskOfActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, object controller, object[] arguments)
System.Threading.Tasks.ValueTask<TResult>.get_Result()
System.Runtime.CompilerServices.ValueTaskAwaiter<TResult>.GetResult()
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask<IActionResult> actionResultValueTask)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

I got to solve the problem like this:我必须像这样解决问题:

foreach (var formName in formsNames)
{
     var form = typeof(DbContext).GetProperty(formName).PropertyType;
     
     var method = typeof(AppointmentsController).GetMethod("RestoreFormInfo");

     // Because the form variable is a DbSet<FormType>, I needed to get the
     // FormType from the GenericTypeArguments array.
     var genericMethod = method.MakeGenericMethod(form.GenericTypeArguments[0]);

     var formResults = await (Task<object>) genericMethod.Invoke(this, new object[] { formName, pacientID, appointmentID });
}

Now, the RestoreFormInfo method is like this:现在, RestoreFormInfo方法是这样的:

public async Task<object> RestoreFormInfo<TEntity>(string formName, string pacientID, int AppointmentID) where TEntity : class
{
     var dataSet = _context.Set<TEntity>();
     
     try
     {
          var results = await dataSet.FromSqlRaw(
               $"SELECT * FROM {formName} WHERE PacientID = '{pacientID}' AND AppointmentID = {appointmentID}")
               .AsNoTracking()
               .FirstAsync();
     }
     catch (InvalidOperationException)
     {
          // The expected error is the "InvalidOperationException: Enumerator failed to MoveNextAsync",
          // it means that the FirstAsync didn't find any result.
          return null;
     }
     
     return results;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用DbSet <T> 具有通用类型 - How to use a DbSet<T> with a generic type 如何将Dependency Injection与EF结合使用以解析具有接口泛型类型的DbSet? - How do you use Dependency Injection with EF to resolve a DbSet with an interfaced generic type? 是否可以将构造函数注入与泛型类型一起使用? - Is it possible to use constructor injection with a generic type? 是否可以将命名元组与泛型类型声明一起使用? - Is it possible to use named Tuple with generic type declaration? 如何在通用存储库中提供实体类型/ dbset类型 - How to provide entity type/dbset type in Generic Repository 是否可以创建一个将项添加到实体框架dbset的通用方法? - Is it possible to create a generic method for adding items to a entity framework dbset? 数据库集.Cast<TEntity> () 错误:无法创建 DbSet<IEntity> 来自“实体”类型对象的非通用 DbSet - DbSet.Cast<TEntity>() Error: Cannot create a DbSet<IEntity> from a non-generic DbSet for objects of type 'Entity' 如何在实体框架中将字符串作为类型DbSet的类型参数传递? - How to pass an string as a type parameter for a generic DbSet in Entity Framework? 是否可以在C#中使用未绑定类型作为泛型类型参数? - Is it possible to use an unbound type as a generic type parameter in C#? 如何将依赖项注入与通用dbset一起使用<T> - How do i use dependency injection with generic dbset<T>
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM