对从数据库请求的类中的列表进行排序

时间:2014-09-09 11:15:33

标签: c# entity-framework

我有一个包含参数列表的类。例如:

public class Container
{
   public List<Parameter> Parameters { get; set; }
}

public class Parameter
{
   puplic string Name {get; set;}
}

通过实体框架从数据库获取的类Сontainer。许多类包含Container。我需要确保包含Сontainer的所有类,并从包含Parameters的排序列表的数据库中检索。也就是说,Container必须对参数或请求步骤进行排序,或者之后立即对其进 如何实现这一目标? 也许写入配置

internal class ContainerConfiguration : EntityTypeConfiguration<Container>
{
    public ContainerConfiguration()
    {
        ToTable("Container");
        HasKey(p => p.Id);
        ... ???
    }
}

或者在数据集中怀疑

        protected override IQueryable<Container> DataSet(DbContext db)
        {
            return db.Set<ProcessMeasurer>()                
                .Include(it => it.Parameters.Select(p => p.Parameter));
        }

2 个答案:

答案 0 :(得分:0)

解决问题的另一个选择:

创建属性并指定默认情况下用于排序的字段:

public class DefaultOrderFieldAttribute : Attribute
{
    public DefaultOrderFieldAttribute()
    {
    }

    public string FieldName { get; set; }
}

[DefaultOrderField(FieldName = "ParameterName")]
public partial class Parameter
{
}

写一个访客,在检测到我们的属性的情况下修改选择:

public class DefaultOrderVisitor : DefaultExpressionVisitor
{
    public override DbExpression Visit(DbScanExpression expression)
    {
        const string NAMESPACE = "OrderTest";

        var type =
            Assembly.GetExecutingAssembly().GetType(string.Format("{0}.{1}", NAMESPACE, expression.Target.Name));

        var attribute =
            type.GetCustomAttributes(typeof (DefaultOrderFieldAttribute)).SingleOrDefault() as
                DefaultOrderFieldAttribute;

        if (attribute != null)
            return expression.OrderBy(ex => ex.Property(attribute.FieldName));

        return expression;
    }
}

加入我们的访客拦截器:

 public class DefaultOrderInterceptor : IDbCommandTreeInterceptor
    {
        public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
        {
            if (interceptionContext.OriginalResult.DataSpace == DataSpace.SSpace)
            {
                var queryCommand = interceptionContext.Result as DbQueryCommandTree;

                if (queryCommand != null)
                {
                    var newQuery = queryCommand.Query.Accept(new DefaultOrderVisitor());
                    interceptionContext.Result = new DbQueryCommandTree(queryCommand.MetadataWorkspace,
                        queryCommand.DataSpace, newQuery);
                }
            }
        }
    }

并在配置中注册(此类只需与模型位于同一个程序集中):

public class EntityFrameworkConfiguration : DbConfiguration
    {
        public EntityFrameworkConfiguration()
        {
            AddInterceptor(new DefaultOrderInterceptor());
        }
    }

答案 1 :(得分:-1)

需要使用实体类。 如果我们想要对包含它的所有元素进行排序,我们必须更改相应的属性。 明显的变体 - 创建属性设置器。

private List<Parameter> _parameters;
public List<Parameter> Parameters
{
   get { return _parameters; }
   set { _parameters = value.OrderBy(...).ToList();
}

但是编译器的行为(调用setter一次,并且多次调用getter)让我有理由假设目标集合不是一次性放入属性中。查询中的项目将逐渐添加到集合中。因此,在setter中排序并不总是有效。 因此,我们必须对返回值进行排序

get
{
   if(_parameters == null) return null;                
   _parameters = _parameters.OrderBy(...).ToList();
   return _parameters;
}

有效。但问题是,当EntityFramework插入每个值时,将对getter进行吸引,从而进行排序。这会影响性能。

目前我所知道的最好的变体是使用函数Prepare继承接口中的所有实体

public interface IEntity
{
   void Prepare();
}

并在每个类模型中实现它。包含其他模型的模型会为每个所需的属性生成一种方法。

public class SomeModel : IEntity
{
   public CustomType SomeProperty { get; set; }
   public OneMoreCustomType AnotherProrerty { get; set; }

   public void Prepare()
   {
      SomeProperty.Prepare();
      AnotherProperty.Prepare();
   }
}

对于相应的课程,将采取适当的行动。包括排序。 Сall在使用之前准备Сontainer(在本例中)的方法。 例如,在业务逻辑(MVPVM)中。