基本问题......
我有一个执行以下代码的方法:
IList<Gig> gigs = GetGigs().WithArtist(artistId).ToList();
GetGigs()方法通过LinqToSql从我的数据库中获取Gigs ......
因此,当执行GetGigs()。WithArtist(artistId).ToList()时,我得到以下异常:
Member access 'ListenTo.Shared.DO.Artist Artist' of 'ListenTo.Shared.DO.Act' not legal on type 'System.Collections.Generic.List`1[ListenTo.Shared.DO.Act]
请注意,扩展功能“WithArtist”如下所示:
public static IQueryable<Gig> WithArtist(this IQueryable<Gig> qry, Guid artistId)
{
return from gig in qry
where gig.Acts.Any(act => (null != act.Artist) && (act.Artist.ID == artistId))
orderby gig.StartDate
select gig;
}
如果我用一个在代码中构建gigs集合的方法替换GetGigs()方法(而不是通过LinqToSQL从数据库构建),我不会得到例外。
所以我很确定问题出在我的LinqToSQl代码而不是对象结构上。
但是,我没有IDEA为什么LinqToSQl版本无法正常工作,所以我在下面列出了所有相关代码。任何帮助都会非常感激地接受!!
LinqToSQL代码......
public IQueryable<ListenTo.Shared.DO.Gig> GetGigs()
{
return from g in DBContext.Gigs
let acts = GetActs(g.ID)
join venue in DBContext.Venues on g.VenueID equals venue.ID
select new ListenTo.Shared.DO.Gig
{
ID = g.ID,
Name = g.Name,
Acts = new List<ListenTo.Shared.DO.Act>(acts),
Description = g.Description,
StartDate = g.Date,
EndDate = g.EndDate,
IsDeleted = g.IsDeleted,
Created = g.Created,
TicketPrice = g.TicketPrice,
Venue = new ListenTo.Shared.DO.Venue {
ID = venue.ID,
Name = venue.Name,
Address = venue.Address,
Telephone = venue.Telephone,
URL = venue.Website
}
};
}
IQueryable<ListenTo.Shared.DO.Act> GetActs()
{
return from a in DBContext.Acts
join artist in DBContext.Artists on a.ArtistID equals artist.ID into art
from artist in art.DefaultIfEmpty()
select new ListenTo.Shared.DO.Act
{
ID = a.ID,
Name = a.Name,
Artist = artist == null ? null : new Shared.DO.Artist
{
ID = artist.ID,
Name = artist.Name
},
GigId = a.GigID
};
}
IQueryable<ListenTo.Shared.DO.Act> GetActs(Guid gigId)
{
return GetActs().WithGigID(gigId);
}
我在下面列出了Act,Artist和Gig对象的代码:
public class Gig : BaseDO
{
#region Accessors
public Venue Venue
{
get;
set;
}
public System.Nullable<DateTime> EndDate
{
get;
set;
}
public DateTime StartDate
{
get;
set;
}
public string Name
{
get;
set;
}
public string Description
{
get;
set;
}
public string TicketPrice
{
get;
set;
}
/// <summary>
/// The Act object does not exist outside the context of the Gig, therefore,
/// the full act object is loaded here.
/// </summary>
public IList<Act> Acts
{
get;
set;
}
#endregion
}
public class Act : BaseDO
{
public Guid GigId { get; set; }
public string Name { get; set; }
public Artist Artist { get; set; }
}
public class Artist : BaseDO
{
public string Name { get; set; }
public string Profile { get; set; }
public DateTime Formed { get; set; }
public Style Style { get; set; }
public Town Town { get; set; }
public string OfficalWebsiteURL { get; set; }
public string ProfileAddress { get; set; }
public string Email { get; set; }
public ImageMetaData ProfileImage { get; set; }
}
public class BaseDO: IDO
{
#region Properties
private Guid _id;
#endregion
#region IDO Members
public Guid ID
{
get
{
return this._id;
}
set
{
this._id = value;
}
}
}
}
答案 0 :(得分:5)
我认为问题是GetGigs中的'let'语句。使用'let'意味着您将最终查询的一部分与要获取的主集分开定义。问题是'let',如果它不是标量,会导致嵌套查询。嵌套查询并不是Linq到sql的最强点,因为它们也被延迟执行。在查询中,将嵌套查询的结果放入要返回的主集的投影中,然后进一步附加linq运算符。
当发生这种情况时,嵌套查询会深入隐藏在将要执行的查询中,这会导致嵌套查询不在要执行的查询的外部投影中,因此必须合并到SQL查询运行到DB上。这是不可行的,因为它是嵌套在主sql查询中的投影中的嵌套查询,并且SQL没有像'投影中的嵌套查询'这样的概念,因为你无法在投影中获取一组元素。 SQL,只有标量。
答案 1 :(得分:5)
我遇到了同样的问题,似乎对我来说诀窍是分离出一个返回IQueryable&lt;&gt;的内联静态方法调用。所以我将这个延迟查询存储到一个变量并引用它。
我认为这是Linq to SQL中的一个错误,但至少有一个合理的解决方法。我还没有对此进行测试,但我的假设是,只有在查询表达式中引用不同类的静态方法时才会出现此问题,无论该函数的返回类型是否为IQueryable&lt;&gt;。所以也许它是持有方法的类,它是问题的根源。就像我说的那样,我无法证实这一点,但可能值得研究。
更新:如果解决方案不明确,我想在原始帖子的示例中指出它。
public IQueryable<ListenTo.Shared.DO.Gig> GetGigs()
{
var acts = GetActs(g.ID); // Don't worry this call is deferred
return from g in DBContext.Gigs
join venue in DBContext.Venues on g.VenueID equals venue.ID
select new ListenTo.Shared.DO.Gig
{
ID = g.ID,
Name = g.Name,
Acts = new List<ListenTo.Shared.DO.Act>(acts),
Description = g.Description,
StartDate = g.Date,
EndDate = g.EndDate,
IsDeleted = g.IsDeleted,
Created = g.Created,
TicketPrice = g.TicketPrice,
Venue = new ListenTo.Shared.DO.Venue {
ID = venue.ID,
Name = venue.Name,
Address = venue.Address,
Telephone = venue.Telephone,
URL = venue.Website
}
};
}
请注意,虽然这应该纠正手头的问题,但似乎还有另一个问题,即在投影的每个元素中访问延迟的行为查询,我猜这将导致每个元素发出单独的查询外投影中的一行。
答案 2 :(得分:1)
我没有在类中看到任何指示LINQ to SQL如何确定哪个列是哪个等等。
您是期望WithArtist
方法在.NET中执行还是转换为SQL?如果您希望将其转换为SQL,则需要使用适当的LINQ to SQL属性修饰Gig类(或以其他方式配置数据上下文)。如果您希望在代码中执行它,只需将第一个参数类型从IQueryable<Gig>
更改为IEnumerable<Gig>
。
答案 3 :(得分:0)
我发现这样的问题(我最近也遇到过)可以解决,如果您将 IQueryable(或表)变量 Gigs
转换为这样的列表
return from g in DBContext.Gigs.ToList()
...
如果仍然不起作用,请对所有 IQueryables 执行相同操作。在我看来,背后的原因是某些查询太复杂而无法转换为 SQL。但是如果你把它“物化”成一个列表,你就可以进行各种查询。
请注意,您应该尽早添加“过滤器”(where 条件),因为过多的内存消耗可能会成为问题。