简体   繁体   English

使用Linq按属性名称和值匹配对象

[英]Matching objects by property name and value using Linq

I need to be able to match an object to a record by matching property names and values using a single Linq query. 我需要能够通过使用单个Linq查询匹配属性名称和值来将对象与记录匹配。 I don't see why this shouldn't be possible, but I haven't been able to figure out how to make this work. 我不知道为什么这不可能,但是我还没弄清楚如何使它工作。 Right now I can do it using a loop but this is slow. 现在,我可以使用循环来执行此操作,但这很慢。

Heres the scenario: 这是场景:

I have tables set up that store records of any given entity by putting their primary keys into an associated table with the key's property name and value. 我设置了一些表来存储任何给定实体的记录,方法是将它们的主键与键的属性名称和值一起放入关联的表中。

If I have a random object at run-time, I need to be able to check if a copy of that object exists in the database by checking if the object has property names that match all of the keys of a record in the database ( this would mean that they would be the same type of object) and then checking if the values for each of the keys match, giving me the same record. 如果我在运行时有一个随机对象,则需要通过检查对象的属性名称是否与数据库中记录的所有键匹配来检查该对象的副本是否存在于数据库中(表示它们将是同一类型的对象),然后检查每个键的值是否匹配,从而得到相同的记录。

Here's how I got it to work using a loop (simplified a bit): 这是我使用循环(略微简化)使其工作的方式:

public IQueryable<ResultDataType> MatchingRecordFor(object entity)
{
    var result = Enumerable.Empty<ResultDataType>();
    var records = _context.DataBaseRecords

    var entityType = entity.GetType();
    var properties = entityType.GetProperties().Where(p => p.PropertyType.Namespace == "System");

    foreach (var property in properties)
    {
        var name = property.Name;
        var value = property.GetValue(entity);
        if (value != null)
        {
            var matchingRecords = records.Where(c => c.DataBaseRecordKeys.Any(k => k.DataBaseRecordKeyName == name && k.DataBaseRecordValue == value.ToString()));
            if (matchingRecords.Count() > 0)
            {
                records = matchingRecords;
            }
        }
    }

    result = (from c in records
                from p in c.DataBaseRecordProperties
                select new ResultDataType()
                {
                    ResultDataTypeId = c.ResultDataTypeID,
                    SubmitDate = c.SubmitDate,
                    SubmitUserId = c.SubmitUserId,
                    PropertyName = p.PropertyName
                });

    return result.AsQueryable();
}

The last statement joins a property table related to the database record with information on all of the properties. 最后一条语句将与数据库记录相关的属性表与所有属性的信息连接在一起。

This works well enough for a single record, but I'd like to get rid of that loop so that I can speed things up enough to work on many records. 这对于单个记录来说已经足够好了,但是我想摆脱那个循环,以便我可以加快速度以处理很多记录。

using System.Reflection;

public IQueryable<ResultDataType> MatchingRecordFor(object entity)
{
    var records = _context.DataBaseRecords;

    var entityType = entity.GetType();
    var properties = entityType.GetProperties().Where(p => p.PropertyType.Namespace == "System");

    Func<KeyType, PropertyInfo, bool> keyMatchesProperty =
       (k, p) => p.Name == k.DataBaseRecordKeyName && p.GetValue(entity).ToString() == k.DataBaseRecordValue;

    var result =
        from r in records
        where r.DataBaseRecordKeys.All(k => properties.Any(pr => keyMatchesProperty(k, pr)))
        from p in r.DataBaseRecordProperties
        select new ResultDataType()
        {
            ResultDataTypeId = r.ResultDataTypeId,
            SubmitDate = r.SubmitDate,
            SubmitUserId = r.SubmitUserId,
            PropertyName = p.PropertyName
        });

    return result.AsQueryable();
}

Hopefully I got that query language right. 希望我正确使用了该查询语言。 You'll have to benchmark it to see if it's more efficient than your original approach. 您必须对其进行基准测试,以查看它是否比原始方法更有效。

edit: This is wrong, see comments 编辑:这是错误的,请参阅评论

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM