基本问题......
我有一个执行以下代码的方法:
IListgigs = 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 IQueryableWithArtist(this IQueryable 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从DB中),我不会得到异常.
所以我很确定问题出在我的LinqToSQl代码而不是对象结构上.
但是,我没有IDEA为什么LinqToSQl版本无法正常工作,所以我在下面列出了所有相关代码.任何帮助都会非常感激地接受!
LinqToSQL代码....
public IQueryableGetGigs() { 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 (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 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 GetActs(Guid gigId) { return GetActs().WithGigID(gigId); }
我在下面列出了Act,Artist和Gig对象的代码:
public class Gig : BaseDO { #region Accessors public Venue Venue { get; set; } public System.NullableEndDate { get; set; } public DateTime StartDate { get; set; } public string Name { get; set; } public string Description { get; set; } public string TicketPrice { get; set; } /// /// The Act object does not exist outside the context of the Gig, therefore, /// the full act object is loaded here. /// public IListActs { 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; } } }
}
我认为问题是GetGigs中的'let'语句.使用'let'意味着您将最终查询的一部分与要获取的主集分开定义.问题是'let',如果它不是标量,会导致嵌套查询.嵌套查询并不是Linq到sql的最强点,因为它们也被延迟执行.在查询中,将嵌套查询的结果放入要返回的主集的投影中,然后进一步附加linq运算符.
当发生这种情况时,嵌套查询会深入隐藏在将要执行的查询中,这会导致嵌套查询不在要执行的查询的外部投影中,因此必须合并到SQL查询中跑进了数据库.这是不可行的,因为它是嵌套在主sql查询中的投影中的嵌套查询,并且SQL没有像'投影中的嵌套查询'这样的概念,因为你无法在投影中获取一组元素. SQL,只有标量.
我遇到了同样的问题,似乎对我来说诀窍是分离出一个返回IQueryable <>的内联静态方法调用,以便将这个延迟查询存储到一个变量中并引用它.
我认为这是Linq to SQL中的一个错误,但至少有一个合理的解决方法.我还没有对此进行测试,但我的假设是,只有在查询表达式中引用不同类的静态方法时才会出现此问题,无论该函数的返回类型是否为IQueryable <>.所以也许它是持有方法的类,它是问题的根源.就像我说的那样,我无法证实这一点,但可能值得研究.
更新:如果解决方案不清楚,我想在原始帖子的示例的上下文中指出它.
public IQueryableGetGigs() { 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 (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 } }; }
请注意,虽然这应该纠正手头的问题,但似乎还有另一个问题,即在投影的每个元素中访问延迟的行为查询,我猜这将导致在每行中向数据库发出单独的查询.外投影.