我想知道使用实体框架和linq创建动态查询的最佳方式是什么。使用实体框架创建动态查询
我想创建一个具有许多排序和过滤参数(超过50)的服务。我将从gui中获得这些对象的填充内容,并且将从单个服务方法执行查询。
我环顾四周我看到我可以动态创建一个字符串,可以在我的方法结束时执行。我不太喜欢这种方式。有一个更好的方法吗?最好使用编译检查键入safe?
我想知道使用实体框架和linq创建动态查询的最佳方式是什么。使用实体框架创建动态查询
我想创建一个具有许多排序和过滤参数(超过50)的服务。我将从gui中获得这些对象的填充内容,并且将从单个服务方法执行查询。
我环顾四周我看到我可以动态创建一个字符串,可以在我的方法结束时执行。我不太喜欢这种方式。有一个更好的方法吗?最好使用编译检查键入safe?
你可以一步一步撰写IQueryable<T>
。假设你有一个FilterDefinition
类,它描述了用户希望如何过滤...
public class FilterDefinition
{
public bool FilterByName { get; set; }
public string NameFrom { get; set; }
public string NameTo { get; set; }
public bool FilterByQuantity { get; set; }
public double QuantityFrom { get; set; }
public double QuantityTo { get; set; }
}
...那么你可以创建一个查询,像这样:
public IQueryable<SomeEntity> GetQuery(FilterDefinition filter)
{
IQueryable<SomeEntity> query = context.Set<SomeEntity>();
// assuming that you return all records when nothing is specified in the filter
if (filter.FilterByName)
query = query.Where(t =>
t.Name >= filter.NameFrom && t.Name <= filter.NameTo);
if (filter.FilterByQuantity)
query = query.Where(t =>
t.Quantity >= filter.QuantityFrom && t.Quantity <= filter.QuantityTo);
return query;
}
您可以考虑使用WCF数据服务创建服务并动态创建URI以查询您的实体模型。
我知道的唯一另外一种方法是根据您的过滤器构建一个IQueryable。
public List<Contact> Get(FilterValues filter)
{
using (var context = new AdventureWorksEntities())
{
IQueryable<Contact> query = context.Contacts.Where(c => c.ModifiedDate > DateTime.Now);
if (!string.IsNullOrEmpty(filter.FirstName))
{
query = query.Where(c => c.FirstName == filter.FirstName);
}
if (!string.IsNullOrEmpty(filter.LastName))
{
query = query.Where(c => c.LastName == filter.LastName);
}
return query.ToList();
}
}
是的,但这是有效的表现明智吗?选择何时执行?到底什么时候ToList()被调用?想象一下,我有非常大的数据集...... – Eduard 2011-04-05 06:38:20
不,这不是性能问题,因为它使用延迟执行来只查询一次。 – BrandonZeider 2011-04-05 12:54:02
+1谢谢你的回答。 – Eduard 2011-04-05 14:05:08
您可以使用动态的规范和动态排序。我已经对他们的博客here和here。下面的例子应该可以帮助你 -
//Assume you're getting following values from search form.
string userSuppliedProperty = "AverageRating";
OperationType userSuppliedOperationType = OperationType.GreaterThan;
var userSuppliedValue = 4.5;
//Create DynamicSpecification from these properties and pass it to repository.
var userFilter = new DynamicSpecification<Product>(userSuppliedProperty, userSuppliedOperationType, userSuppliedValue);
var filteredProducts = _repository.Get(userFilter);
//You can also combine two specifications using either And or Or operation
string userSuppliedProperty2 = "Category";
OperationType userSuppliedOperationType2 = OperationType.EqualTo;
var userSuppliedValue2 = "Keyboard";
var userFilter2 = new DynamicSpecification<Product>(userSuppliedProperty2, userSuppliedOperationType2, userSuppliedValue2);
var combinedFilter = userFilter.And(userFilter2);
var filteredProducts2 = _repository.Get(combinedFilter);
//and it support dynamic sorting
string userSuppliedOrderingProperty = "Category";
OrderType userSuppliedOrderType = OrderType.Ascending;
var sortedFilteredProducts = _repository.Get(combinedFilter, o => o.InOrderOf(userSuppliedOrderingProperty, userSuppliedOrderType));
我不知道搜索对象/ DTO你得到,但你可以很容易地创建一个通用搜索对象/ DTO,并可以将其映射到几行GenericSpecification的对象链的代码。过去我曾经使用过WCF服务,它对我来说工作得非常好。
谢谢,但是这个工作怎么样?这不是从数据库中提取所有数据,然后逐步缩小到所需的一组数据? – Eduard 2011-04-05 06:36:52
@ t-edd:不,它利用“延迟执行”(http://blogs.msdn.com/b/charlie/archive/2007/12/09/deferred-execution.aspx)。这意味着在上面的例子中构成的'IQueryable'只是一个描述数据如何过滤的查询表达式。查询的真正执行完全不在本例中。您执行查询,然后通过将“贪婪”运算符应用于'IQueryable ',例如'query.ToList()'。此时 - 而不是更早 - 查询表达式被翻译成SQL并发送到服务器。 –
Slauma
2011-04-05 10:03:21
这不是很好,因为它假设'SomeEntity'具有名称和数量字段,所以这只是一半的动态。 – 2017-01-23 17:56:57