[英]How to map multiple entities from LINQ query into a new entity using a common map method
以下代码与我的解决方案非常相似,不同之处仅在于“ 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);
};
}
}
}
我认为您不应该创建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
等)之后,此操作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();
这意味着Linq To SQL无法MapEntity()
调用映射到相等的SQL表达式。
您需要从Linq To SQL中获取数据(也许可以通过查询包含JOIN
的VIEW
来完成,这很容易做到),并且在接收到数据并将其存储在内存后(在List
),然后将其映射到EntityC
数据类型。
另外,您可以通过将整个表读入内存中来下载列表entitiesA和entityB,如下所示:
entitiesA = DbContext.EntitiesA.ToList();
entitiesB = DbContext.EntitiesB.ToList();
然后,您可以继续使用所使用的表达式,因为现在使用的是内存中列表,因此使用的是常规LINQ to Object,而不是LINQ to SQL。
谢谢大家花一点时间写一个可能的解决方案和/或评论。 所有的想法都很棒。 实际上,原始代码按预期方式工作。 问题是我不是用平凡的参数而是使用三次运算符来调用映射函数。 就像是:
Select(entity => MapEntityC(entity.entityB,
(entity.entityA != null) ? entity.entityA : new EntityA()));
LINQ to SQL无法转换为SQL语句。 一旦删除该表达式并使用了一个简单的表达式,该代码就会起作用。 再次感谢您。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.