gpt4 book ai didi

c# - 动态选择器 Linq To Entities

转载 作者:行者123 更新时间:2023-11-30 15:28:12 25 4
gpt4 key购买 nike

我有一个生成匿名类型的动态选择器表达式。它在 linq to objects 中工作正常,但在 linq to entities 中,它抛出:

尝试 1

NotSupportedException

Only parameterless constructors and initializers are supported in LINQ to Entities.

Expression<Func<User, T>> DynamicSelect<T>(T obj, ParameterExpression userParam)
{
var newExpression = Expression.New(
typeof(T).GetConstructor(typeof(T).GenericTypeArguments),
userParam,
Expression.Constant("X"),
Expression.Constant("Y")
);
return Expression.Lambda<Func<User, T>>(newExpression, userParam);
}

var userParam = Expression.Parameter(typeof(User), "u");
var obj = new { User = new User(), Address = string.Empty, Fax = string.Empty };
var arr = context.Set<T>()
.Select(DynamicSelect(obj, userParam))
.ToArray();

尝试 2,如果我创建一个自定义类型,它可以工作,但我不想这样做,因为我想重用这个辅助方法而不为每个实体创建额外的自定义类型,我想要能够根据消费者传递类型。

public class Container
{
public User User { get; set; }
public string Address { get; set; }
public string Fax { get; set; }
}
Expression<Func<User, T>> DynamicSelect<T>(T obj, ParameterExpression userParam)
{
var initExpression = Expression.MemberInit(
Expression.New(typeof(T)),
Expression.Bind(typeof(T).GetProperty("User"), userParam),
Expression.Bind(typeof(T).GetProperty("Address"), Expression.Constant("X")),
Expression.Bind(typeof(T).GetProperty("Fax"), Expression.Constant("Y"))
);
return Expression.Lambda<Func<User, T>>(initExpression, userParam);
}

var userParam = Expression.Parameter(typeof(User), "u");
var arr = context.Set<T>()
.Select(DynamicSelect<Container>(null, userParam))
.ToArray();

尝试 3,我也尝试使用 Tuple<User, string, string> , 但也不支持。

NotSupportedException

LINQ to Entities does not recognize the method 'System.Tuple`3[User,System.String,System.String] Create[User,String,String](User, System.String, System.String)' method, and this method cannot be translated into a store expression.

Expression<Func<User, T>> DynamicSelect<T>(T obj, ParameterExpression userParam)
{
var createExpression = Expression.Call(
typeof(Tuple),
"Create",
typeof(T).GenericTypeArguments,
userParam,
Expression.Constant("X"),
Expression.Constant("Y"));
return Expression.Lambda<Func<User, T>>(createExpression, userParam);
}

var userParam = Expression.Parameter(typeof(User), "u");
var arr = context.Set<User>()
.Select(DynamicSelect<Tuple<User, string, string>>(null, userParam))
.ToArray();

请帮忙。

更新

我试图在任何消费者(用户、客户、合作伙伴等)中重用此辅助方法,而无需针对每个消费者进行具体实现。

类结构看起来像。

public class User
{
public int Id { get; set; }
public string UserName { get; set; }
public virtual ICollection<Contact> Contacts { get; set; }
}
public class Customer
{
public int Id { get; set; }
public string CompanyName { get; set; }
public virtual ICollection<Contact> Contacts { get; set; }
}
public class Contact
{
public int Id { get; set; }
public string Type { get; set; }
public string Content { get; set; }
}
public class UserDto
{
public int Id { get; set; }
public string UserName { get; set; }
public ContactDto Contact { get; set; }
}
public class CustomerDto
{
public int Id { get; set; }
public string CompanyName { get; set; }
public ContactDto Contact { get; set; }
}
public class ContactDto
{
public string Email { get; set; }
public string Address { get; set; }
public string Fax { get; set; }
// other contact informations
}

我有很多联系人,每个消费者的联系人可能不同。

var users = context.Set<User>()
.Select(x => new UserDto
{
Id = x.Id,
UserName = x.UserName,
Contact = new ContactDto
{
Email = x.Contacts.Where(c => c.Type == "Email").Select(c => c.Value).FirstOrDefault()
}
})
.ToArray();

var customers = context.Set<Customer>()
.Select(x => new CustomerDto
{
Id = x.Id,
CompanyName = x.CompanyName,
Contact = new ContactDto
{
Address = x.Contacts.Where(c => c.Type == "Address").Select(c => c.Value).FirstOrDefault(),
Fax = x.Contacts.Where(c => c.Type == "Fax").Select(c => c.Value).FirstOrDefault(),
}
})
.ToArray();

并重构了 x.Contacts.Where(c => c.Type == "Address").Select(c => c.Value).FirstOrDefault()到表达式中,但我不能在方法中直接使用它,例如:

var users = context.Set<User>()
.Select(x => new UserDto
{
Id = x.Id,
UserName = x.UserName,
Contact = new ContactDto
{
Email = GetContactExpression("Email").Compile()(x)
}
})
.ToArray();

它会抛出错误因为Invoke linq to expression 不支持方法,因此我需要重构整个 Select表达式,但我需要使它通用( UserUserName ,但是 CustomerCompanyName ,以及任何其他信息)并且可能在这个问题解决后也传递联系人类型。目前预期的结果会有点儿小:

var obj = new { User = new User(), Email = "" };
var users = context.Set<User>()
.Select(x => DynamicSelect(obj))
.Select(x => new UserDto
{
Id = x.User.Id,
UserName = x.User.UserName,
Contact = new ContactDto
{
Email = x.Email
}
})
.ToArray();

最佳答案

当我将你的表达式与编译器为 u => new { User = u, Address = "X", Fax = "Y"} 创建的表达式进行比较时,区别在于后者已填充 Members

我不太明白 Members 存在的原因是什么,但我会尝试设置它,我猜它会解决你的问题。代码可能类似于:

var constructor = typeof(T).GetConstructor(typeof(T).GenericTypeArguments);

var newExpression = Expression.New(
constructor,
new Expression[] { userParam, Expression.Constant("X"), Expression.Constant("Y") },
constructor.GetParameters().Select(p => typeof(T).GetProperty(p.Name)));

关于c# - 动态选择器 Linq To Entities,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26127218/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com