EF中查询NotMapped标记列引发异常的解决方案咨询
解决EF通用CRUD中重复描述检查的异常问题
问题根源
你遇到的System.NotSupportedException是因为标记了[NotMapped]的ID属性并未被EF的LINQ查询提供者识别——EF无法将这个未映射的属性转换为对应的SQL字段,自然无法执行查询。另外EF禁止两个属性映射同一列,是为了避免数据同步冲突,这个方案从一开始就行不通。
下面是两种可行的解决思路:
思路1:通过实体提供主键表达式动态构建查询
在通用接口中去掉未映射的ID属性,改为要求每个实体返回自身主键的表达式,让LINQ查询能正确识别数据库字段:
- 定义通用接口
public interface IGenericTable { string Description { get; set; } // 每个实体实现该属性,返回自身主键的表达式 Expression<Func<T, object>> PrimaryKeyExpression<T>() where T : IGenericTable; }
- 实体类实现接口(以ProductType为例)
public class ProductType : IGenericTable { public int ProductTypeID { get; set; } public string Description { get; set; } public Expression<Func<T, object>> PrimaryKeyExpression<T>() where T : IGenericTable { return x => ((ProductType)x).ProductTypeID; } }
- 编写通用重复检查方法
public bool IsDescriptionDuplicate<T>(DbContext context, T entity) where T : class, IGenericTable { var dbSet = context.Set<T>(); var primaryKeyExpr = entity.PrimaryKeyExpression<T>() as Expression<Func<T, object>>; // 构建描述匹配条件 var param = Expression.Parameter(typeof(T), "x"); var descriptionMatch = Expression.Equal( Expression.Property(param, nameof(IGenericTable.Description)), Expression.Constant(entity.Description) ); // 构建主键排除条件(新增时主键为默认值,编辑时排除自身) var pkProperty = ((MemberExpression)primaryKeyExpr.Body).Member as PropertyInfo; var currentPkValue = pkProperty.GetValue(entity); var pkNotMatch = Expression.NotEqual( Expression.Property(param, pkProperty.Name), Expression.Constant(currentPkValue) ); // 合并条件并执行查询 var combinedCondition = Expression.AndAlso(descriptionMatch, pkNotMatch); var query = dbSet.Where(Expression.Lambda<Func<T, bool>>(combinedCondition, param)); return query.Any(); }
思路2:利用EF元数据自动获取主键信息
如果不想让实体类额外实现主键表达式,可以直接从EF的模型元数据中读取实体的主键字段,完全不需要实体做额外修改(只要实现包含Description的IGenericTable接口即可):
public bool IsDescriptionDuplicate<T>(DbContext context, T entity) where T : class, IGenericTable { var dbSet = context.Set<T>(); var entityModel = context.Model.FindEntityType(typeof(T)); var primaryKey = entityModel.FindPrimaryKey().Properties.First(); // 假设为单主键场景 var pkProperty = typeof(T).GetProperty(primaryKey.Name); var currentPkValue = pkProperty.GetValue(entity); // 构建查询条件 var param = Expression.Parameter(typeof(T), "x"); var condition = Expression.AndAlso( Expression.Equal( Expression.Property(param, nameof(IGenericTable.Description)), Expression.Constant(entity.Description) ), Expression.NotEqual( Expression.Property(param, primaryKey.Name), Expression.Constant(currentPkValue) ) ); return dbSet.Any(Expression.Lambda<Func<T, bool>>(condition, param)); }
这个方法的优势是通用性更强,无需每个实体都编写主键表达式,EF会自动从数据模型中识别主键字段。
内容的提问来源于stack exchange,提问作者Disti
相关产品推荐
相关产品推荐

