问题在于在一系列元素中获取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;而且我不知道如何构建表达式。
答案 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>();