LinqToSQl和成员访问在类型异常上不法律的

2w3rbyxf  于 2023-04-27  发布在  其他
关注(0)|答案(4)|浏览(109)

最基本的问题…
我有一个方法,它执行以下代码:

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;
    }

如果我将GetGigs()方法替换为一个在code中构造gig集合的方法(而不是通过LinqToSQL从DB中),我不会得到异常。
所以我相当肯定问题出在我的LinqToSQl代码上,而不是对象结构。
然而,我不知道为什么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;
        }
    }



}

}

r8xiu3jd

r8xiu3jd1#

我认为问题是GetGigs中的'let'语句。使用'let'意味着您将最终查询的一部分与要获取的主集合分开定义。问题是'let',如果它不是标量,则会导致嵌套查询。嵌套查询实际上不是Linq to sql的最强点,因为它们也会延迟执行。在您的查询中,您将嵌套查询的结果放入要返回的主集合的投影中,然后进一步追加LINQ运算符。
当THAT发生时,嵌套查询被更深地埋在将被执行的查询中,并且这导致嵌套查询不在要执行的查询的外部投影中并且因此必须被合并到在DB上运行的SQL查询中的情况。这是不可行的。因为它是嵌套在主SQL查询内的投影中的嵌套查询,并且SQL没有像“投影中的嵌套查询”这样的概念,因为你不能在SQL中获取投影中的一组元素,只能获取标量。

kq0g1dla

kq0g1dla2#

我也遇到了同样的问题,对我来说,解决问题的办法似乎是分离出一个返回IQueryable〈〉的内联静态方法调用,这样我就可以将这个延迟查询存储到一个变量中并引用它。
我认为这是Linq to SQL中的一个bug,但至少有一个合理的解决方案。我还没有测试过这个问题,但我的假设是,只有当在查询表达式中引用不同类的静态方法时,无论该函数的返回类型是否为IQueryable〈〉,才会出现这个问题。因此,可能是持有方法的类是问题的根源。就像我说的,我还不能证实这一点,但它可能值得调查。

**更新:**以防解决方案不清楚,我想在原始帖子的示例中指出它。

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 
               }

           };
}

请注意,虽然这应该纠正了手头的问题,但似乎还存在另一个问题,即延迟行为查询在投影的每个元素中被访问,我猜这将导致对外部投影中的每行数据库发出单独的查询。

70gysomp

70gysomp3#

我在你的类中没有看到任何东西表明LINQ to SQL是如何计算出哪一列是哪一列的。
您是否希望WithArtist方法在.NET中执行,或转换为SQL?如果您希望将其转换为SQL,则需要使用适当的LINQ to SQL属性装饰Gig类(或以其他方式配置数据上下文)。如果您希望在代码中执行它,只需将第一个参数类型从IQueryable<Gig>更改为IEnumerable<Gig>

fgw7neuy

fgw7neuy4#

我发现,如果将IQueryable(或Table)变量Gigs转换为如下所示的列表,就可以解决这样的问题(我最近也遇到过)

return from g in DBContext.Gigs.ToList()
...

如果仍然不起作用,对所有IQueryables执行相同的操作。在我看来,背后的原因似乎是有些查询太复杂而无法转换为SQL。但是如果您将其“具体化”为列表,则可以执行任何类型的查询。
要小心,您应该尽早添加“过滤器”(where条件),因为过多的内存消耗可能会成为一个问题。

相关问题