如何在复杂类型的Entity的每个字段中搜索特定值?

时间:2015-03-01 03:35:05

标签: c# linq

喜欢这个主题。我需要遍历实体的每个属性和复杂类型的属性,并检查它的值是否与给定值相似。我做了类似这样的事情,但效率非常低,在三个记录表中找到值需要1-2秒。如何制作更快?我尝试将其重写为linq,但每次尝试都失败了。

    private List<AddressBook> SearchContact(string searchText)
    {
        var ToReturn = new List<AddressBook>();
        using (var cntx = Model.DBService.Instance.CreateContext())
        {

            foreach (var s in cntx.AddressBooks.ToList())
            {
                Type AddressBookProperties = s.GetType();
                Type PersonInfoProperties = s.PersonInfo.GetType();
                Type AddressProperties = s.Address.GetType();
                foreach (PropertyInfo prop in AddressBookProperties.GetProperties())
                {
                    try
                    {
                        if (prop.GetValue(s).ToString().Contains(searchText))
                        {
                            ToReturn.Add(s);
                            break;
                        }
                    }
                    catch { }
                }
                foreach (PropertyInfo prop in PersonInfoProperties.GetProperties())
                {
                    try
                    {
                        if (prop.GetValue(s).ToString().Contains(searchText))
                        {
                            ToReturn.Add(s);
                            break;
                        }
                    }
                    catch { }
                }
                foreach (PropertyInfo prop in AddressProperties.GetProperties())
                {
                    try
                    {
                        if (prop.GetValue(s).ToString().Contains(searchText))
                        {
                            ToReturn.Add(s);
                            break;
                        }
                    }
                    catch { }
                }
            }
        }
        return ToReturn;
    }

型号:

public class AddressBook
{
    public AddressBook()
    {
        this.Address = new Address();
        this.PersonInfo = new PersonInfo();
    }
    [Key]
    public int AddressBookID { get; set; }

    public Address Address { get; set; }
    public PersonInfo PersonInfo { get; set; }
    public String RecordName { get; set; }
    public Boolean isPerson { get; set; }
    public Boolean isFirm { get; set; }
    public virtual Template Template { get; set; }
}

public class PersonInfo
{
    private string fullName { get; set; }

    public string Fullname
    {
        get
        {
            if (fullName == null)
            {
                fullName = Firstname + " " + Surname;
                return Firstname + " " + Surname;
            }
            return fullName;
        }
        set
        {
            fullName = value;   
        }
    }
    public string Firstname { get; set; }
    public string Surname { get; set; }
    public string Email { get; set; }
    public string ExtField { get; set; }
    public string Phone { get; set; }
    public string NIP { get; set; }
    public string MobilePhone { get; set; }
    public string Fax { get; set; }
}

public class Address
{
    public string CompanyName { get; set; }
    public string Street { get; set; }

    public string HouseNumber { get; set; }
    public string FlatNumber { get; set; }

    public string PostalCode { get; set; }

    public string Country { get; set; }
    public string PostOffice { get; set; }
    public string Commune { get; set; }

    public string City { get; set; }}

1 个答案:

答案 0 :(得分:1)

您可以通过构建动态表达式树来完成此操作,以便在数据库上完成所有处理。这里有一些代码可以帮助您入门:

private static IEnumerable<Expression> GetConditions(Expression instance, Expression searchTerm)
{
    // note: if you have properties like FullName that don't map directly
    // to database columns, you'll need to filter those out here
    var stringProperties = @object.Type.GetProperties()
        .Where(p => p.PropertyType == typeof(string));

    // GetMethod from 
    // http://www.codeducky.org/10-utilities-c-developers-should-know-part-two/
    var containsMethod = Helpers.GetMethod((string s) => s.Contains(default(string)));

    // for each property, generate an expression 
    // instance.Prop.Contains(searchTerm)
    return stringProperties.Select(p => 
        Expression.Call(
            Expression.MakeMemberAccess(instance, p),
            containsMethod,
            searchTerm
        )
    );
}

// use the above method like so:
var bookParameter = Expression.Parameter(typeof(AddressBook));
var personInfo = Expression.MakeMemberAccess(
    bookParameter, 
    typeof(AddressBook).GetProperty("PersonInfo")
);
// ... create more for other complex types
var searchTermExpression = Expression.Constant(searchTerm);

var allConditions = GetConditions(bookParameter, searchTermExpression)
    .Concat(GetConditions(personInfo, searchTermExpression))
    // ... add conditions for other complex types

// combine the conditions into a single expression with OR:
// ab.RecordName.Contains(...) || ab.PersonInfo.Name.Contains(...)...
var combinedCondition = allConditions.Aggregate(Expression.OrElse);

// create a lambda which you can pass to Where()
// ab => ab.RecordName.Contains(...) || ab.PersonInfo.Name.Contains(...)...
var lambda = Expression.Lambda<Func<AddressBook, bool>>(
    combinedCondition,
    bookParameter
);

// filter the query
var filtered = ctxt.AddressBooks.Where(lambda);