使用泛型属性

时间:2015-06-19 13:37:35

标签: c# linq entity-framework generics

问题在于在一系列元素中获取Max值。 对象的类型未知,属性遵循约定<EntityName>_Id

目前我解决了这个问题:

public static int GetMaxId<TEntity>()
{
    try
    {
        var key = typeof(TEntity).Name;
        var adapter = (IObjectContextAdapter)MyDbContext;
        var objectContext = adapter.ObjectContext;
        // 1. we need the container for the conceptual model
        var container = objectContext.MetadataWorkspace.GetEntityContainer(
            objectContext.DefaultContainerName, System.Data.Entity.Core.Metadata.Edm.DataSpace.CSpace);
        // 2. we need the name given to the element set in that conceptual model
        var name = container.BaseEntitySets.Where((s) => s.ElementType.Name.Equals(key)).FirstOrDefault().Name;
        // 3. finally, we can create a basic query for this set
        var query = objectContext.CreateQuery<TEntity>("[" + name + "]");

        // working with result
        var baseEntity = container.BaseEntitySets.Where((s) => s.ElementType.Name.Equals(key)).FirstOrDefault();
        var property = baseEntity.ElementType.Members.FirstOrDefault(_property => _property.Name.EndsWith("Id"));

        var tmpResult = query.ToList();

        var currentMaxID = tmpResult.Max(element =>
        {
            PropertyInfo pInfo = typeof(TEntity).GetProperty(property.Name);
            int value = (int)pInfo.GetValue(element);

            return value;
        });

        return currentMaxID;
    }
    catch (Exception ex)
    {
        string exMessage = "GetMaxId.Exception";
        EntityModelDataProviderLogger.Fatal(exMessage, ex);
        throw;
    }
}

有更好/更清洁的方法吗?

我已经阅读过有关动态表达式的内容,但对我来说并不是那么清楚。

LINQ expression with generic property此示例比较日期。就我而言,我只有一个元素&#34;而且我不知道如何构建表达式。

2 个答案:

答案 0 :(得分:1)

这很长,我不能在这里测试一下:

public static int GetMaxId<TEntity>()
{
    try
    {
        var key = typeof(TEntity).Name;
        var adapter = (IObjectContextAdapter)MyDbContext;
        var objectContext = adapter.ObjectContext;

        // 1. we need the container for the conceptual model
        var container = objectContext.MetadataWorkspace.GetEntityContainer(
            objectContext.DefaultContainerName, System.Data.Entity.Core.Metadata.Edm.DataSpace.CSpace);
        // 2. we need the name given to the element set in that conceptual model
        var baseEntity = container.BaseEntitySets.Single(s => s.ElementType.Name == key);
        // 3. finally, we can create a basic query for this set
        var query = objectContext.CreateQuery<TEntity>("[" + baseEntity.Name + "]");

        // Looking for the property
        string propertyId = baseEntity.Name + "_" + "Id";
        // The PropertyInfo connected to the EdmMember
        PropertyInfo property = (PropertyInfo)typeof(TEntity).GetProperty(propertyId);

        // Building the Expression
        ParameterExpression par = Expression.Parameter(typeof(TEntity));
        MemberExpression prop = Expression.Property(par, property);

        // cast to (int?)property
        // Note the use of int?, because the table could be empty!
        UnaryExpression conv = Expression.Convert(prop, typeof(int?));

        // An expression like x => x.Entity_Id
        Expression<Func<TEntity, int?>> lambda = Expression.Lambda<Func<TEntity, int?>>(conv, par);

        int? currentMaxID = ((IQueryable<TEntity>)query).Max(lambda);

        // We change null to 0
        return currentMaxID ?? 0;
    }
    catch (Exception ex)
    {
        string exMessage = "GetMaxId.Exception";
        EntityModelDataProviderLogger.Fatal(exMessage, ex);
        throw;
    }
}

如果它有效,我会解释它是如何工作的?

请注意,您正在做的是在概念上错误 ...您使用ToList()选择所有表格,然后在本地查找Max()。这段代码创建了一个表达式树来执行Max()数据库端。

答案 1 :(得分:0)

我将使用属性Id定义一个接口,并在方法上添加一个约束,以仅接受该接口的类型。这消除了对脆弱命名约定的需要,并使反射变得不必要。

public interface IEntity
{
    int Id { get; set; }
}

public static int GetMaxId<TEntity>() where TEntity : IEntity
{
    return MyDbContext.Set<TEntity>().AsEnumerable().Max(e => e.Id);
}

public Entity : IEntity
{
    public int MyId { get; set;}

    public int Id { get{ return MyId; } set{ MyId = value; } }
}

用法:

var max = GetMaxId<Entity>();