linq / lambda表达式的泛型类

时间:2015-01-07 20:50:20

标签: c# linq generics lambda

C#Entity framework 4.0

我有一个包含10个表的数据库,其中包含2个常用列'id'和'modstamp'

访问表格中的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”作为任何表格?

4 个答案:

答案 0 :(得分:2)

首先,您需要让所有实体实现一个接口或一个包含IDModStamp属性的抽象类,让我们调用它{{ 1}}:

Stampable

此时,你需要为你的方法做的就是让它实现泛型输入:

public abstract class Stampable 
{
  [Key]
  public int ID { get; set; } 

  [Required]
  public string ModStamp { get; set; }
}

答案 1 :(得分:0)

如果我理解正确,您需要Set<T>DbContext的属性:

首先,使用idmodstamp属性创建所有实体类的基类。然后:

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();
    }
}

但是你必须为这种方法使用代码优先范例。

答案 2 :(得分:0)

另一种选择是通过c#的部分类功能为您的实体类添加一个新属性。

所以生成的实体定义可能如下所示,注意我不知道你的ModStamp列的实际DataType是什么:

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创建这样的代码的Partial.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获取属性,就像我为公司实体所做的那样。

答案 3 :(得分:0)

这是一个使用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)

如果您愿意只返回找到的实体,则可以删除TSelectorField,然后在检索后从项目中获取ModStamp。这将删除一个表达式树方法和一个主方法上的泛型输入。

正如其他人建议的那样,你可以去接口路由并使用那个例子,它会更简单。