以下代码与我在解决方案中的代码非常相似,不同之处仅在于“entitiesA”和“entitiesB”集合的值使用LINQ数据上下文存储在SQL Server数据库中。代码在控制台应用程序中工作得很好,但是当从数据库中检索值时,系统会将“无法将表达式'...'转换为SQL,并且不能将其视为本地表达式。”我做错了什么?
using System;
using System.Collections.Generic;
using System.Linq;
namespace LinqSelectDemo
{
class EntityA
{
public int ID { get; set; }
public string StringValue { get; set; }
}
class EntityB
{
public int ID { get; set; }
public int? EntityAID { get; set; }
public int IntValue { get; set; }
}
class EntityC
{
public int ID { get; set; }
public string StringValue { get; set; }
public int IntValue { get; set; }
}
class Program
{
static List<EntityA> entitiesA;
static List<EntityB> entitiesB;
static EntityC MapEntityC(EntityB entityB, EntityA entityA = null)
{
if (entityA == null)
{
entityA = entitiesA.FirstOrDefault(entity => (entity.ID == entityB.EntityAID));
}
return new EntityC()
{
ID = ((entityA != null) ? entityA.ID : 0) + ((entityB != null) ? entityB.ID : 0),
StringValue = (entityA != null) ? entityA.StringValue : null,
IntValue = (entityB != null) ? entityB.IntValue : int.MinValue
};
}
static void Main(string[] args)
{
entitiesA = new List<EntityA>()
{
new EntityA() { ID = 11, StringValue = "string1" },
new EntityA() { ID = 12, StringValue = "string2" },
new EntityA() { ID = 13, StringValue = "string3" },
};
entitiesB = new List<EntityB>()
{
new EntityB() { ID = 21, IntValue = 1, EntityAID = 11 },
new EntityB() { ID = 22, IntValue = 2 },
new EntityB() { ID = 23, IntValue = 3, EntityAID = 13 },
};
List<EntityC> entitiesC1 = entitiesB.GroupJoin(entitiesA, entityB => entityB.EntityAID, entityA => entityA.ID, (entityB, entityA) => new { entityB, entityA = entityA.SingleOrDefault() })
.Select(entity => MapEntityC(entity.entityB, entity.entityA))
.ToList();
List<EntityC> entitiesC2 =
(
from entityB in entitiesB
join entityA in entitiesA on entityB.EntityAID equals entityA.ID into tempEntitiesA
from entityA in tempEntitiesA.DefaultIfEmpty()
select MapEntityC(entityB, entityA)
).ToList();
foreach (EntityC entityC in entitiesC1)
{
Console.WriteLine("ID: {0}, StringValue: '{1}', IntValue: {2}", entityC.ID, entityC.StringValue, entityC.IntValue);
};
Console.WriteLine();
foreach (EntityC entityC in entitiesC2)
{
Console.WriteLine("ID: {0}, StringValue: '{1}', IntValue: {2}", entityC.ID, entityC.StringValue, entityC.IntValue);
};
}
}
}
答案 0 :(得分:1)
我认为您不应该创建linq-to-objects
和linq-to-entities
兼容查询。即使它们看起来相似,但在功能上它们完全不同。所以说,我提出的解决方案将忽略linq-to-objects
方面的事情。
第一步是创建一个包含两个实体的类。在这种情况下EntityA
和EntityB
public class EntityBandA
{
public EntityB EntityB { get;set; }
public EntityA EntityA { get;set; }
}
现在我们需要创建一个IQueryable
转换方法。此方法的目的是将新IQueryable<EntityBandA>
转换为IQueryable<EntityC>
。注意 - 只有在我们对其进行迭代时才会对数据库运行(即ToList
,FirstOrDefault
等...)。
static IQueryable<EntityC> MapEntityC(IQueryable<EntityBandA> query)
{
var query = from e in query
select new EntityC()
{
ID = e.EntityA.ID + e.EntityB,
StringValue = e.EntityA.StringValue,
IntValue = e.EntityB != null ? entityB.IntValue : int.MinValue
};
return query;
}
请注意,我们删除了一些空检查。使用linq-to-entities
时不需要它们,因为我们的表达式被翻译成sql。如果未找到任何值,则会选择默认值。 (Int:0, String:null
)
现在我们需要调整您当前的应用程序以使用我们的新方法
IQueryable<EntityBandA> queryBandA = entitiesB.GroupJoin(entitiesA, entityB => entityB.EntityAID, entityA => entityA.ID,
(entityB, entityA) => new EntityBandA
{
EntityB = entityB,
EntityA = entityA.SingleOrDefault()
});
List<EntityC> entitiesC1 = MapEntityC(queryBandA).ToList();
答案 1 :(得分:0)
这意味着Linq To SQL无法将对MapEntity()
的调用映射到相同的SQL表达式。
您需要从Linq To SQL获取数据(可能通过查询包含VIEW
的{{1}},这很容易),并且在您收到它并且它在内存中之后(在JOIN
)中,然后将其映射到List
数据类型。
ALTERNATIVELY 您可以通过将整个表读入内存来下载实体A和实体B列表,如下所示:
EntityC
然后你可以继续使用你已经使用过的表达式,因为你现在正在使用内存列表,因此定期使用LINQ to Objects而不是LINQ to SQL。
答案 2 :(得分:0)
感谢大家花一点时间撰写可能的解决方案和/或评论。所有想法都很棒。实际上原始代码就像假设一样。问题是我使用一个简单的参数调用映射函数,而不是使用一个terciary运算符表达式。类似的东西:
Select(entity => MapEntityC(entity.entityB,
(entity.entityA != null) ? entity.entityA : new EntityA()));
LINQ to SQL无法转换为SQL语句。一旦我删除了该表达式并使用了一个简单的表达式,代码就可以工作了。再次感谢你。