Entity Framework 6:多主键场景下通用DbSet.Find方法调用问题
解决Entity Framework通用增改方法中多主键调用DbSet.Find()的问题
这个问题我之前也碰到过!核心原因是DbSet.Find()方法接受的是**params object[]类型的参数**,而你当前的代码要么只传了单个主键值,要么直接传递了List<object>,多主键场景下自然会触发参数类型错误。下面分两步给出解决方案:
一、直接修复当前代码:正确传递多主键参数
你只需要修改GenericAddOrUpdate方法中调用Find的代码,把收集到的主键值列表转换成数组传递即可:
private void GenericAddOrUpdate<T>(ICollection<T> values, params string[] keyValues) where T : class { foreach (var value in values) { try { var keyList = new List<object>(); foreach (var keyValue in keyValues) { var propertyInfo = value.GetType().GetProperty(keyValue); var propertyValue = propertyInfo.GetValue(value); keyList.Add(propertyValue); } var someDbSet = _DbContext.Set(typeof(T)); // 关键修改:将List<object>转为object[]传递给Find var current = someDbSet.Find(keyList.ToArray()); if (current == null) { someDbSet.Add(value); } else { _DbContext.Entry(current).CurrentValues.SetValues(value); } } catch (Exception e) { throw; } } _DbContext.SaveChanges(); }
这样调用GenericAddOrUpdate(result, "BusinessSystemId", "CaseId", "Action", "Cycle", "RateNo")时,所有主键值会被正确传递给Find方法,完美适配多主键模型。
二、进阶优化:自动获取主键属性,避免手动传参
手动传递主键字段名容易出现拼写错误,我们可以利用EF的元数据自动识别实体的主键,让方法更通用、更健壮:
private void GenericAddOrUpdate<T>(ICollection<T> values) where T : class { // 获取当前实体的EF元数据 var entityType = _DbContext.Model.FindEntityType(typeof(T)); // 获取主键属性集合(复合键会按配置的Column(Order)顺序返回) var keyProperties = entityType.FindPrimaryKey().Properties; foreach (var value in values) { try { // 反射获取每个主键属性的值,自动按顺序组装成数组 var keyValues = keyProperties .Select(p => p.PropertyInfo.GetValue(value)) .ToArray(); var dbSet = _DbContext.Set<T>(); var current = dbSet.Find(keyValues); if (current == null) { dbSet.Add(value); } else { _DbContext.Entry(current).CurrentValues.SetValues(value); } } catch (Exception e) { // 建议添加日志记录,方便后续排查错误 throw; } } _DbContext.SaveChanges(); }
调用示例
现在调用时无需传递任何主键字段名,方法会自动识别实体的主键配置:
internal void AddOrUpdateClassifications() { var result = _IntegrationApiService.GetClassifications(); GenericAddOrUpdate(result); } internal void AddOrUpdateFeeCalculations(string businessSystemId, int caseId) { var result = _IntegrationApiService.GetFeeCalculation(businessSystemId, caseId); GenericAddOrUpdate(result); }
注意事项
- 确保你的实体类已经通过
[Key]特性(或Fluent API)正确配置了主键,EF才能准确识别主键属性。 - 复合主键的顺序会和你配置的
Column(Order = N)顺序一致,Find方法会按此顺序匹配参数,无需担心顺序问题。
内容的提问来源于stack exchange,提问作者Ogglas
相关产品推荐
相关产品推荐

