使用 LINQ 使搜索方法通用

发布于 2024-11-05 03:25:16 字数 331 浏览 0 评论 0 原文

我的项目中有一个反复重复的方法:

public PAC PAC_GetByCodiPac(string codiPac)

{

var sel = _gam.PAC.Where(pac => pac.CODI_PAC == codiPac);

            if (sel.Count() > 0)
                return sel.First();
            return null;
        }

表 PAC 意味着(患者),所以我对我拥有的所有表都有这些方法。 我怎样才能为此制定一个通用方法? 提前致谢。

I have a method in my project that repeats over and over:

public PAC PAC_GetByCodiPac(string codiPac)

{

var sel = _gam.PAC.Where(pac => pac.CODI_PAC == codiPac);

            if (sel.Count() > 0)
                return sel.First();
            return null;
        }

The table PAC means (patient), so I have these methods for all the tables I have.
How can I make a generic method for this?
Thanks in advance.

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

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

发布评论

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

评论(5

强辩 2024-11-12 03:25:16

这是您的通用方法。请注意,正如其他人指出的那样 FirstOrDefault 比 count and then first 更好,所以我在这里使用它。但也可以编写表达式,使其模仿原始代码的功能。如果您需要其他帮助,请告诉我。

public static T GetByCodi<T>(IQueryable<T> table, string codi, string fieldName) where T : class
{
    // x
    ParameterExpression parameter = Expression.Parameter(typeof(T), "x");
    Expression currentExpression = parameter;
    Type currentType = typeof(T);
    PropertyInfo property = currentType.GetProperty(fieldName);

    // x.CODI_xxx
    currentExpression = Expression.Property(currentExpression, property);

    // x.CODI_xxx == codi
    currentExpression = Expression.Equal(currentExpression, Expression.Constant(codi));

    // x => x.CODI_xxx == codi
    LambdaExpression lambdaExpression = Expression.Lambda(currentExpression, parameter);

    return table.FirstOrDefault((Func<T, bool>)lambdaExpression.Compile());
}

您可以像这样使用它:

PAC xxx = GetByCodi<PAC>(_gam.PAC, codiPac, "CODI_PAC");

编辑 1
我根据注释更改了代码,以便您可以传入任意ID字段名称。

Here is your generic method. Note, that as others pointed out FirstOrDefault is better than count and then first, so I'm using it here. But it's also possible to write the expression so that it mimics what your original code does. Please let me know if you need additional help with this.

public static T GetByCodi<T>(IQueryable<T> table, string codi, string fieldName) where T : class
{
    // x
    ParameterExpression parameter = Expression.Parameter(typeof(T), "x");
    Expression currentExpression = parameter;
    Type currentType = typeof(T);
    PropertyInfo property = currentType.GetProperty(fieldName);

    // x.CODI_xxx
    currentExpression = Expression.Property(currentExpression, property);

    // x.CODI_xxx == codi
    currentExpression = Expression.Equal(currentExpression, Expression.Constant(codi));

    // x => x.CODI_xxx == codi
    LambdaExpression lambdaExpression = Expression.Lambda(currentExpression, parameter);

    return table.FirstOrDefault((Func<T, bool>)lambdaExpression.Compile());
}

You use it like this:

PAC xxx = GetByCodi<PAC>(_gam.PAC, codiPac, "CODI_PAC");

Edit 1:
I changed the code according to the comment so that you can pass arbitrary ID field name in.

伤感在游骋 2024-11-12 03:25:16

我发现您要求的是一个非常直接的 where 查询,甚至不需要将其放在单独的方法上。
您还可以简单地增强您的查询链接如下:

public PAC PAC_GetByCodiPac(string codiPac)
{
   return _gam.PAC.FirstOrDefault(pac => pac.CODI_PAC == codiPac);
}

FirstOrDefault 将返回数组中的第一项,如果不是,它将返回 null。

I see that what you asked is a very straight forward where query even doesn't require to have have it on a separate method.
Also you can simply enhance your query link the following:

public PAC PAC_GetByCodiPac(string codiPac)
{
   return _gam.PAC.FirstOrDefault(pac => pac.CODI_PAC == codiPac);
}

FirstOrDefault will return the first item on the array, if not it will return null.

萌化 2024-11-12 03:25:16

如果您想要一个通用方法来指定任何表以及该表中记录的任何谓词,那么您实际上找不到比内置 Where(...) 更好的方法了。以及(正如其他人已经指出的那样)FirstOrDefault(...) 扩展方法。

然后,您的代码将如下所示:

var result = _gam.PAC.Where(pac => pac.CODI_PAC == codiPac).FirstOrDefault();
// OR
var result = _gam.PAC.FirstOrDefault(pac => pac.CODI_PAC == codiPac);

编写您自己的通用方法时,您可以获得的最好的结果将是这样:

public T FirstOrDefault<T>(IQueryable<T> source,
    Expression<Func<T, bool>> predicate)
{
    return source.Where(predicate).FirstOrDefault();
    // OR
    // return source.FirstOrDefault(predicate);
}

这实际上是多余的。特别是当您的调用代码实际上使用辅助方法会更长时:

var result = FirstOrDefault(_gam.PAC, pac => pac.CODI_PAC == codiPac);
// versus
var result = _gam.PAC.FirstOrDefault(pac => pac.CODI_PAC == codiPac);

更糟糕的是,您的代码不再使用流畅的可组合语法。这只会使可读性和维护变得更加困难。

如果您坚持使用 IQueryable 扩展方法,那么您可以像这样进行组合:

var result = _gam.PAC
        .Where(pac => pac.CODI_PAC == codiPac)
        .Where(pac => pac.SomeOtherProperty == someOtherValue)
        .FirstOrDefault();
// OR

var result = (from pac in _gam.PAC
              where pac.CODI_PAC == codiPac
              where pac.SomeOtherProperty == someOtherValue
              select pac).FirstOrDefault();

这里需要注意的一件非常重要的事情是 predicate 参数在 >IQueryable.Where(...) 扩展方法的类型为 Expression>。这允许 IQueryable 提供程序在返回结果之前的最后一刻构建本机 SQL(或其他本机提供程序查询)。

不使用 Expression> 意味着您的查询将与此等效:

var result =
    _gam.PAC
        .ToArray()
        .Where(pac => pac.CODI_PAC == codiPac)
        .FirstOrDefault();

这意味着查询将在选择之前将“PAC”表中的每条记录加载到内存中第一个过滤结果并丢弃其余结果。

最重要的是,通过创建通用帮助器方法,您将重写现有框架代码,并且会面临性能和维护问题,同时也会降低代码可读性< /强>。

我希望这有帮助。

If you want a generic method that lets you specify any table and any predicate for records from that table then you can't really get any better than the built-in Where<T>(...) and (as others have already pointed out) the FirstOrDefault<T>(...) extension methods.

Your code would then look like so:

var result = _gam.PAC.Where(pac => pac.CODI_PAC == codiPac).FirstOrDefault();
// OR
var result = _gam.PAC.FirstOrDefault(pac => pac.CODI_PAC == codiPac);

The best you could get then, writing your own generic method, would be this:

public T FirstOrDefault<T>(IQueryable<T> source,
    Expression<Func<T, bool>> predicate)
{
    return source.Where(predicate).FirstOrDefault();
    // OR
    // return source.FirstOrDefault(predicate);
}

And that is really just redundant. Especially when your calling code would be actually longer using the helper method:

var result = FirstOrDefault(_gam.PAC, pac => pac.CODI_PAC == codiPac);
// versus
var result = _gam.PAC.FirstOrDefault(pac => pac.CODI_PAC == codiPac);

And even worse, your code is no longer using a fluent, composable syntax. This just makes readability and maintenance more difficult.

If you stick with using the IQueryable<T> extension methods then you can do composition like this:

var result = _gam.PAC
        .Where(pac => pac.CODI_PAC == codiPac)
        .Where(pac => pac.SomeOtherProperty == someOtherValue)
        .FirstOrDefault();
// OR

var result = (from pac in _gam.PAC
              where pac.CODI_PAC == codiPac
              where pac.SomeOtherProperty == someOtherValue
              select pac).FirstOrDefault();

One very important thing to note here is that the predicate parameter in the IQueryable<T>.Where<T>(...) extension method is of type Expression<Func<T, bool>>. This allows the IQueryable<T> provider to construct the native SQL (or other native provider query) at the very last moment before returning a result.

Not using Expression<Func<T, bool>> means that your query would be the equivalent of this:

var result =
    _gam.PAC
        .ToArray()
        .Where(pac => pac.CODI_PAC == codiPac)
        .FirstOrDefault();

And that would mean the query will load every record from the "PAC" table into memory before selecting the first filtered result and throwing out the rest of the results.

The bottom-line is that by making a generic helper method you are rewriting existing framework code and you open yourself to performance and maintenance issues while also reducing code readability.

I hope this helps.

怀里藏娇 2024-11-12 03:25:16

我不确定您是否要求这样做,但该方法可以位于静态类和方法中,因此您可以从任何地方调用它。

I'm not sure if you are asking for this, but this method could be in a static class and method and so you'd be able to call it from everywhere.

辞慾 2024-11-12 03:25:16

一个简单的解决方案是:

//a generic method
private PAC PAC_GetPAC(Func<PAC, bool> predicate)
{
   return _gam.PAC.Where(predicate).FirstOrDefault();
}

public PAC PAC_GetPACById(long id)
{
   return PAC_GetPAC(p => p.ID == id);
}

public PAC PAC_GetByCodiPac(string codiPac)
{
   return PAC_GetPAC(p => pac.CODI_PAC == codiPac);
}

An easy solution will be:

//a generic method
private PAC PAC_GetPAC(Func<PAC, bool> predicate)
{
   return _gam.PAC.Where(predicate).FirstOrDefault();
}

public PAC PAC_GetPACById(long id)
{
   return PAC_GetPAC(p => p.ID == id);
}

public PAC PAC_GetByCodiPac(string codiPac)
{
   return PAC_GetPAC(p => pac.CODI_PAC == codiPac);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文