如何使用用户定义的条件查询对象集合?

发布于 2024-09-29 02:21:55 字数 966 浏览 8 评论 0原文

抱歉,如果这有点抽象。我正处于发展的早期阶段。

我有两种对象类型:

  1. 需要存储一系列用户定义条件的对象。
  2. 与第一个对象中定义的零个或多个条件匹配的对象。

这是一个简单的例子,说明它是如何运行的。

  1. 用户创建多个类型 2 的对象并将它们添加到集合中。
  2. 然后用户创建类型 1 的对象并为其分配多个条件。
  3. 系统使用对象类型 1 中的条件生成类型 2 的对象列表,按每个对象匹配条件的百分比排序。

以下是预期输出的示例:

Conditions                                            List
Quantity >= 2                                         Object5 100%
Value < 2                                             Object2  75%
Category = "Blah"                                     Object4  50%
Quality > 5                                           Object1  25%
                                                      Object3   0%

每个条件中的第一个操作数是属性的名称,而第二个操作数是该属性的值。

我怎样才能做到这一点?

我的第一个想法是它看起来类似于查询语言。如果它们是数据库表中的记录,我可以为每个条件拼接一个 SQL 字符串,运行每个查询并计算每个记录 ID 在查询结果中出现的次数。但这些都是普通的旧 C# 对象。我还没有决定使用什么来持久化对象,所以我现在不想把自己束缚在数据库引擎上。有什么建议吗?

Sorry if this is a little abstract. I'm in the early stages of development.

I have two object types:

  1. An object that needs to store a series of user defined conditions.
  2. An object that matches zero or more of the conditions defined in the first object.

Here's a simple example of how it would run.

  1. A user creates several objects of type 2 and adds them to a collection.
  2. Then the user creates an object of type 1 and assigns several conditions to it.
  3. The system uses the conditions in object type 1 to generate a list of objects of type 2 sorted by what percentage of the conditions each object matches.

Here is a sample of the expected output:

Conditions                                            List
Quantity >= 2                                         Object5 100%
Value < 2                                             Object2  75%
Category = "Blah"                                     Object4  50%
Quality > 5                                           Object1  25%
                                                      Object3   0%

The first operand in each condition is the name of a property while the second operand is the value of that property.

How can I accomplish this?

My first thought is that it looks similar to a query language. If they were records in a DB table I could stitch together an SQL string for each condition, run each query and count the number of times each record id showed up in the query results. But these are plain old C# objects. I haven't decided on what to use for object persistence yet so I'd rather not tie myself to a db engine at this point. Any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

乙白 2024-10-06 02:21:55

这听起来像是 LINQ 就是您想要使用的。特别是,我会研究 LINQ To ObjectsLINQ To SQL(如果最终选择持久性存储)。

This sounds like LINQ is what you want to use. In particular, I would look into LINQ To Objects and LINQ To SQL if a persistence store is eventually chosen.

画中仙 2024-10-06 02:21:55

另外,还有一篇关于如何直接执行 SQL 查询 (LINQ to SQL)

Northwnd db = new Northwnd(@"c:\northwnd.mdf");
IEnumerable<Customer> results = db.ExecuteQuery<Customer>
(@"SELECT c1.custid as CustomerID, c2.custName as ContactName
    FROM customer1 as c1, customer2 as c2
    WHERE c1.custid = c2.custid"
);

also, there is an article on how Directly Execute SQL Queries (LINQ to SQL)

Northwnd db = new Northwnd(@"c:\northwnd.mdf");
IEnumerable<Customer> results = db.ExecuteQuery<Customer>
(@"SELECT c1.custid as CustomerID, c2.custName as ContactName
    FROM customer1 as c1, customer2 as c2
    WHERE c1.custid = c2.custid"
);
小…红帽 2024-10-06 02:21:55

下面是在字符串上使用 LINQ-to-Objects 的示例实现:

var conditions = new Func<string, bool>[]
{
    s => s.Length < 4,                  // less than 4 characters
    s => s.Count(c => c == 'o') > 2,    // more than 2 'o's
    s => s == "fooo",                   // is "fooo"
    s => s.Contains('b'),               // contains 'b'
};
var words = new[] { "foo", "fooo", "foooo", "bar", "barr", "bazooo" };
var query = words.Select(Word => new
                                 {
                                     Word,
                                     Percentage = conditions.Average(c => c(Word) ? 1M : 0M)
                                 })
                 .Where(p => p.Percentage > 0)          // keep words matches some conditions
                 .OrderByDescending(p => p.Percentage)  // order by the percentage
                 .ThenBy(p => p.Word);                  // then order in alphabetical order

回想起来,我认为这个示例也可以与 LINQ-to-SQL 一起使用(对 conditions 数组进行一些调整)。

这只是一个简单的例子,但您当然可以进一步扩展这个想法。

Here's an example implementation using LINQ-to-Objects on strings:

var conditions = new Func<string, bool>[]
{
    s => s.Length < 4,                  // less than 4 characters
    s => s.Count(c => c == 'o') > 2,    // more than 2 'o's
    s => s == "fooo",                   // is "fooo"
    s => s.Contains('b'),               // contains 'b'
};
var words = new[] { "foo", "fooo", "foooo", "bar", "barr", "bazooo" };
var query = words.Select(Word => new
                                 {
                                     Word,
                                     Percentage = conditions.Average(c => c(Word) ? 1M : 0M)
                                 })
                 .Where(p => p.Percentage > 0)          // keep words matches some conditions
                 .OrderByDescending(p => p.Percentage)  // order by the percentage
                 .ThenBy(p => p.Word);                  // then order in alphabetical order

In retrospect, I think this example might work with LINQ-to-SQL too (with some tweaks on the conditions array).

This was just a quick example but you can certainly expand on the idea even more.

安稳善良 2024-10-06 02:21:55

您可以使用规范模式的修改版本来执行此操作。从将结果表示为百分比的界面开始:

public interface ISpecification<T>
{
    double GetPercentSatisfiedBy(T target);
}

接下来,创建一个应用任意条件的规范:

public sealed class Specification<T> : ISpecification<T>
{
    private readonly Func<T, bool> _predicate;

    public Specification(Func<T, bool> predicate)
    {
        _predicate = predicate;
    }

    public double GetPercentSatisfiedBy(T target)
    {
        return _predicate(target) ? 1 : 0;
    }
}

现在,创建一个线性组合其他规范结果的规范:

public sealed class CompositeSpecification<T> : ISpecification<T>
{
    private readonly IList<ISpecification<T>> _specifications;

    public CompositeSpecification(params ISpecification<T>[] specifications)
    {
        _specifications = specifications.ToList();
    }

    public double GetPercentSatisfiedBy(T target)
    {
        return _specifications.Average(
            specification => specification.GetPercentSatisfiedBy(target));
    }
}

最后,构建一个包含所有所需条件并应用的规范它到 Foo 对象列表:

var specification = new CompositeSpecification<Foo>(
    new Specification<Foo>(foo => foo.Quantity >= 2),
    new Specification<Foo>(foo => foo.Value < 2),
    new Specification<Foo>(foo => foo.Category == "Blah"),
    new Specification<Foo>(foo => foo.Quality > 5));

var foos = new List<Foo> { ... };

var results =
    from foo in foos
    let percentSatisfied = specification.GetPercentSatisfiedBy(foo)
    orderby percentSatisfied descending
    select new
    {
        Foo = foo,
        PercentSatisfied = percentSatisfied
    };

此设计支持任意复杂度的规范。

You can do this with a modified version of the Specification pattern. Start out with an interface that expresses results as percentages:

public interface ISpecification<T>
{
    double GetPercentSatisfiedBy(T target);
}

Next, create a specification which applies any arbitrary condition:

public sealed class Specification<T> : ISpecification<T>
{
    private readonly Func<T, bool> _predicate;

    public Specification(Func<T, bool> predicate)
    {
        _predicate = predicate;
    }

    public double GetPercentSatisfiedBy(T target)
    {
        return _predicate(target) ? 1 : 0;
    }
}

Now, create a specification which linearly combines the results of other specifications:

public sealed class CompositeSpecification<T> : ISpecification<T>
{
    private readonly IList<ISpecification<T>> _specifications;

    public CompositeSpecification(params ISpecification<T>[] specifications)
    {
        _specifications = specifications.ToList();
    }

    public double GetPercentSatisfiedBy(T target)
    {
        return _specifications.Average(
            specification => specification.GetPercentSatisfiedBy(target));
    }
}

Finally, build a specification which contains all of your desired conditions and apply it to a list of Foo objects:

var specification = new CompositeSpecification<Foo>(
    new Specification<Foo>(foo => foo.Quantity >= 2),
    new Specification<Foo>(foo => foo.Value < 2),
    new Specification<Foo>(foo => foo.Category == "Blah"),
    new Specification<Foo>(foo => foo.Quality > 5));

var foos = new List<Foo> { ... };

var results =
    from foo in foos
    let percentSatisfied = specification.GetPercentSatisfiedBy(foo)
    orderby percentSatisfied descending
    select new
    {
        Foo = foo,
        PercentSatisfied = percentSatisfied
    };

This design supports specifications of arbitrary complexity.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文