有没有办法将 Linq 投影与扩展方法一起使用

发布于 2024-08-18 21:21:29 字数 1769 浏览 7 评论 0原文

我正在尝试使用 AutoMapper 和存储库模式以及流畅的界面,但在 Linq 投影方面遇到了困难。就其价值而言,当仅使用内存中的对象时,此代码可以正常工作。然而,当使用数据库提供程序时,它会在构造查询图时中断。我尝试了 SubSonic 和 Linq to SQL,但结果相同。感谢您的想法。

这是在所有场景中使用的扩展方法 - 这是问题的根源,因为不使用扩展方法一切都工作正常

public static IQueryable<MyUser> ByName(this IQueryable<MyUser> users, string firstName)
{
     return from u in users
            where u.FirstName == firstName
            select u;
}

这是工作正常的内存中代码

var userlist = new List<User> {new User{FirstName = "Test", LastName = "User"}};

Mapper.CreateMap<User, MyUser>();
var result = (from u in userlist
                   select Mapper.Map<User, MyUser>(u))
                   .AsQueryable()
                   .ByName("Test");

foreach (var x in result)
{
     Console.WriteLine(x.FirstName);
}

这里是使用 SubSonic(或 Linq to SQL 或其他)的同样的事情失败了。这就是我想通过扩展方法以某种方式完成的工作...

Mapper.CreateMap<User, MyUser>();

var result = from u in new DataClasses1DataContext().Users
                          select Mapper.Map<User, MyUser>(u);

var final = result.ByName("Test");
foreach(var x in final) // Fails here when the query graph built.
{
     Console.WriteLine(x.FirstName);
}

这里的目标是避免必须手动将生成的“User”对象映射到“MyUser”域对象 - 换句话说,我我正在尝试找到一种使用 AutoMapper 的方法,因此我在需要数据库读取操作的任何地方都没有这种映射代码:

var result = from u in new DataClasses1DataContext().Users
                          select new MyUser // Can this be avoided with AutoMapper AND extension methods?  
                          {
                             FirstName = v.FirstName,
                             LastName = v.LastName
                          };

I'm trying to use AutoMapper and a repository pattern along with a fluent interface, and running into difficulty with the Linq projection. For what it's worth, this code works fine when simply using in-memory objects. When using a database provider, however, it breaks when constructing the query graph. I've tried both SubSonic and Linq to SQL with the same result. Thanks for your ideas.

Here's an extension method used in all scenarios - It's the source of the problem since everything works fine without using extension methods

public static IQueryable<MyUser> ByName(this IQueryable<MyUser> users, string firstName)
{
     return from u in users
            where u.FirstName == firstName
            select u;
}

Here's the in-memory code that works fine

var userlist = new List<User> {new User{FirstName = "Test", LastName = "User"}};

Mapper.CreateMap<User, MyUser>();
var result = (from u in userlist
                   select Mapper.Map<User, MyUser>(u))
                   .AsQueryable()
                   .ByName("Test");

foreach (var x in result)
{
     Console.WriteLine(x.FirstName);
}

Here's the same thing using a SubSonic (or Linq to SQL or whatever) that fails. This is what I'd like to make work somehow with extension methods...

Mapper.CreateMap<User, MyUser>();

var result = from u in new DataClasses1DataContext().Users
                          select Mapper.Map<User, MyUser>(u);

var final = result.ByName("Test");
foreach(var x in final) // Fails here when the query graph built.
{
     Console.WriteLine(x.FirstName);
}

The goal here is to avoid having to manually map the generated "User" object to the "MyUser" domain object- in other words, I'm trying to find a way to use AutoMapper so I don't have this kind of mapping code everywhere a database read operation is needed:

var result = from u in new DataClasses1DataContext().Users
                          select new MyUser // Can this be avoided with AutoMapper AND extension methods?  
                          {
                             FirstName = v.FirstName,
                             LastName = v.LastName
                          };

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

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

发布评论

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

评论(1

感情洁癖 2024-08-25 21:21:29

嗯,我不知道 SubSonic 的 LINQ 实现。然而,问题的原因可能是 LINQ 提供程序无法使用“Mapper”调用。它期望一些可以翻译成 SQL 的东西。

顺便说一句,我会在“用户”查询上使用 .ByName() 而不是当前的实现。因为目前必须映射结果才能运行 .ByName()。因此,您从数据库中检索大量用户实例,映射它们并随后过滤它们。如果您在“用户”上使用 .ByName,它可以被转换为 SQL,而无需检索。

所以我猜这样的事情会起作用:

public static IQueryable<User> ByName(this IQueryable<User> users,
                                      string firstName)
{
    return from u in users
        where u.FirstName == firstName
        select u;
}

现在你将映射部分添加到末尾:
Mapper.CreateMap();

var result = from u in new DataClasses1DataContext().Users.ByName("Test")
                select Mapper.Map<User, MyUser>(u);
// now the 'ByName'-constain can be ran on the database

foreach(var x in result)
{
     Console.WriteLine(x.FirstName);
}

如果仍然不起作用,您可能需要强制 Mapper 部分使用 LINQ-to-Object:
Mapper.CreateMap();

var result = DataClasses1DataContext().Users.ByName("Test").ToList();
// now the result is a regualar list, so LINQ-to-object is used for the mapping part

var final = from u in result
                   select Mapper.Map<User, MyUser>(u);

foreach(var x in final)
{
     Console.WriteLine(x.FirstName);
}

顺便说一句,您可能想添加一个“SubSonic”标签,以便 SubSonic 专家回答您的问题。

Well I don't know SubSonic's LINQ-implementation. However the cause of the problem could be, that the LINQ-Provider fails to use the 'Mapper'-call. It expects something that is can be translated into SQL.

By the way, I would use the .ByName() on the 'User'-query instead of the current implementation. Because currently the result has to mapped in order to run the .ByName(). So you retrieve a lot of User-instance from the database, map them and filter them afterwards. If you would use .ByName on the 'User', it can be translated into SQL an never has to be retrieved.

So my guess it that something like this would work:

public static IQueryable<User> ByName(this IQueryable<User> users,
                                      string firstName)
{
    return from u in users
        where u.FirstName == firstName
        select u;
}

And now you add the mapping part to the end:
Mapper.CreateMap();

var result = from u in new DataClasses1DataContext().Users.ByName("Test")
                select Mapper.Map<User, MyUser>(u);
// now the 'ByName'-constain can be ran on the database

foreach(var x in result)
{
     Console.WriteLine(x.FirstName);
}

If it still doesn't work, you might need to force the usage of LINQ-to-Object for the Mapper-part:
Mapper.CreateMap();

var result = DataClasses1DataContext().Users.ByName("Test").ToList();
// now the result is a regualar list, so LINQ-to-object is used for the mapping part

var final = from u in result
                   select Mapper.Map<User, MyUser>(u);

foreach(var x in final)
{
     Console.WriteLine(x.FirstName);
}

By the way, you might wanna add a 'SubSonic'-tag, so that the SubSonic-experts answer your question.

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