c# - EF Core Generic Context.Find 用于 CRUD(创建/检索/更新/删除)视图
问题描述
考虑以下情况,其中控制器是 generic<T, U> where T : DbContext where U : class, new()
注意:这适用于当您有许多表时的场景,比如说在您正在搭建的某些现有数据库中,25+ 甚至高达 100+,并且您希望在后端有一个管理 CRUD 视图以用于列出/添加/更新/deleting 为每个表记录相同的记录,不需要更新,因为在运行像 Scaffold-DbContext 这样的工具时,DbContext 模型中的数据库架构会发生变化。
[Route("Get/{id}")]
public async Task<IActionResult> Get(string id)
{
var entityType = Context.Model.GetEntityTypes().Where(x => x.ClrType.Name == typeof(U).Name).FirstOrDefault();
var keyProperty = entityType.FindPrimaryKey().Properties.ToArray()[0];
var key = Convert.ChangeType(id, keyProperty.PropertyInfo.PropertyType);
var result = Context.Find(typeof(U), new object[] { key });
return new JsonResult(result);
}
如果需要,您如何使其一般支持主键中的多个字段?有没有更清洁的方法来完成上述操作?
更新,将 ChangeType 更改为 TypeDescriptor,为 Find 添加了多个键:
[Route("Get/{id}")]
public async Task<IActionResult> Get(string id)
{
string[] keysStr = id.Split(',');
var entityType = Context.Model.GetEntityTypes().Where(x => x.ClrType.Name == typeof(U).Name).FirstOrDefault();
var keyProperties = entityType.FindPrimaryKey().Properties.ToArray();
List<dynamic> keys = new List<object>();
if (keysStr.Length != keyProperties.Length)
{
throw new ArgumentException("Keys must be comma-separated and must be of the same number as the number of keys in the table.");
}
for(int i=0;i<keyProperties.Length;i++)
{
//var key = Convert.ChangeType(id, keyProperty.PropertyInfo.PropertyType);
TypeConverter converter = TypeDescriptor.GetConverter(keyProperties[i].PropertyInfo.PropertyType);
var key = converter.ConvertFromString(id);
keys.Add(key);
}
var result = Context.Find(typeof(U), keys.ToArray());
return new JsonResult(result);
}
使用 string.Split(',') 分隔 Route 中的多个关键字段。更好的方法?
解决方案
虽然看起来可行,但我建议不要使用这种方法。尤其成问题的是 CRUD 的“C”和“U”:你将如何检查类失效?例如,用户可能会提交 a Birthday
in the future 或 a StartDate
after
EndDate
,而您将无法阻止它,或者至少这会很棘手,尤其是在复杂的前提条件下,例如“状态 S 的父实体不得超过 N孩子们”。
如果您仍然想这样做,请考虑让客户端指定实体类型。
像这样的东西:
[ApiController]
[Route("any")]
public class JackOfAllTradesCOntroller : ControllerBase
{
private readonly MyContext _ctx;
public JackOfAllTradesCOntroller(MyContext ctx)
{
_ctx = ctx;
// Add a random entity.
// Customer configured with:
// modelBuilder.Entity<Customer>().HasKey(new[] { "Id", "FirstName" });
_ctx.Customers.Add(
new Customer() {
Id = 1,
FirstName = Guid.NewGuid().ToString().Substring(1,6),
LastName = Guid.NewGuid().ToString(),
Address = "Addr"
});
_ctx.SaveChanges();
}
private IEntityType GetType(string typeName)
{
return _ctx.Model.GetEntityTypes()
.Where(x => x.ClrType.Name == typeName).First();
}
[Route("GetAll/{entityType}")]
public IActionResult GetAll(string entityType)
{
IEntityType eType = GetType(entityType);
MethodInfo set = _ctx.GetType().GetMethod("Set")
.MakeGenericMethod(eType.ClrType);
object result = set.Invoke(_ctx, new object[0]);
return new JsonResult(result);
}
[Route("Get/{entityType}")]
public IActionResult Get(
string entityType,
[FromQuery(Name = "id")] string[] id)
{
IEntityType eType = GetType(entityType);
IProperty[] keyProperties = eType.FindPrimaryKey().Properties.ToArray();
// ... validate id here ...
object[] keys = id.Zip(
keyProperties,
(i, p) => Convert.ChangeType(i, p.PropertyInfo.PropertyType)
).ToArray();
object result = _ctx.Find(eType.ClrType, keys);
return new JsonResult(result);
}
}
演示:
推荐阅读
- spinnaker-halyard - 如何解决大三角帆中给定的错误?部署在 kubernetes 上的大三角帆,8084 和 9000 是我提供的端口。hal deploy connect 出现错误
- javascript - 使用 jQuery 反转 CSS 动画
- typescript - 如何使用打字稿命名空间模拟模块?
- python - 如何使用 Python 将日期、时间、序列、部分等写入 csv 文件?
- python-3.x - 如何在 Python 中读取目录中的先前文件?
- javascript - API 距离矩阵仅在 Javascript 中调用
- python - 带有外来符号的 Countvectorizer 在词汇词典中提供交换的键值
- sql - 如何计算列 q.atindt 和 q.orderdate 之间的天数?因为在某些情况下我没有得到正确的数字
- github - 在 Github 上跟踪对私有存储库的贡献
- facebook-opengraph - Facebook 无法读取由 nextjs 生成的开放图标签