linq / lambda 表达式的泛型类
本文关键字:泛型类 表达式 lambda linq | 更新日期: 2023-09-27 18:36:50
C# 实体框架 4.0
我有一个包含 10 个表格的数据库,其中包含 2 个公共列"id"和"modstamp"
访问表中的模戳我有一个函数
protected internal override string GetModStampinChild(int sid)
{
DBContext sq = new DBContext();
return sq.xxxx.Where(s => s.id == sid)
.Select(s => s.modstamp).SingleOrDefault().ToModStampString();
}
其中每个表的 xxxx 都会更改。我目前正在为每个表覆盖此函数。
有没有办法使用某种通用的"类",我可以在"xxxx"是任何表的地方使用?
首先
,您需要让所有实体实现一个接口或包含ID
和ModStamp
属性的抽象类,我们称之为Stampable
:
public abstract class Stampable
{
[Key]
public int ID { get; set; }
[Required]
public string ModStamp { get; set; }
}
此时,您需要做的就是让您的方法实现泛型类型:
protected internal override string GetModStampInChild<T>(int sid) where T : Stampable
{
using (var sq = new DbContext())
{
return sq.Set<T>.Where(s => s.id == sid)
.Select(s => s.modstamp)
.SingleOrDefault()
.ToModStampString();
}
}
如果我理解正确,你需要一个DbContext
类的属性Set<T>
:
首先,创建具有id
和modstamp
属性的所有实体类的基类。然后:
protected internal override string GetModStampInChild<T>(int sid) where T : BaseEntity
{
using (var sq = new DbContext())
{
return sq.Set<T>.Where(s => s.id == sid)
.Select(s => s.modstamp)
.SingleOrDefault()
.ToModStampString();
}
}
但是,必须对此方法使用代码优先范例。
另一种选择是通过 c# 的分部类功能向实体类添加新属性。
所以生成的实体定义可能如下所示,请注意,我不知道您的 ModStamp 列的实际数据类型是什么:
public partial class Company
{
public int Id { get; set; }
public byte[] ModStamp { get; set; }
public string Name { get; set; }
public string City { get; set; }
public string State { get; set; }
}
记下要转换的 ModStamp 列。
然后将 EF 创建如下代码的 Part.cs 文件添加到文件中,请注意,我不知道您实际上想用 ModStamp 值做什么:
public static class ModConverter
{
public static string ToModStampString(byte[] modStamp)
{
return BitConverter.ToString(modStamp);
}
}
public partial class Company
{
public string ModStampString
{
get
{
return ModConverter.ToModStampString(this.ModStamp);
}
}
}
然后,您必须手动为每个具有 ModStamp 列的实体添加新的 ModStampString Get 属性,就像我为公司实体所做的那样。
下面是一个解决方案,它在 DbContext 和表达式树上使用 Set 方法来动态查询该对象。
private Expression<Func<TArg, bool>> CreatePredicate<TArg, TPredicateField>(string fieldName, TPredicateField value)
{
ParameterExpression parameter = Expression.Parameter(typeof(TArg), "o");
MemberExpression memberExpression = Expression.Property(parameter, fieldName);
var condition = Expression.Equal(memberExpression, Expression.Constant(value));
var lambda = Expression.Lambda<Func<TArg, bool>>(condition, parameter);
return lambda;
}
private Expression<Func<TArg, TPredicateField>> CreateSelector<TArg, TPredicateField>(string fieldName)
{
ParameterExpression parameter = Expression.Parameter(typeof(TArg), "o");
Expression propertyExpr = Expression.Property(parameter, fieldName);
var lambda = Expression.Lambda<Func<TArg, TPredicateField>>(propertyExpr, parameter);
return lambda;
}
public TSelectorField GetModStamp<TEntity, TPredicateField, TSelectorField>(TPredicateField id) where TEntity : class
{
using (var ctx = new OnTheFlyEntities("Data Source=(local);Initial Catalog=AscensionBO;Integrated Security=True;MultipleActiveResultSets=True"))
{
var predicate = CreatePredicate<TEntity, TPredicateField>("Id", id);
var selector = CreateSelector<TEntity, TSelectorField>("ModStamp");
TSelectorField item = ctx.Set<TEntity>().Where(predicate).Select(selector).SingleOrDefault();
return item;
}
}
然后你可以像这样称呼它:
GetModStamp<Entity2, int, string>(1)
如果您愿意只返回找到的实体,则可以消除 TSelector字段,然后在检索到项目后从项目中获取 ModStamp。 这将删除一个表达式树方法和一个主方法上的泛型输入。
正如其他人建议的那样,您可以走接口路线并使用该示例,它会简单得多。