当前位置:  开发笔记 > 数据库 > 正文

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

如何解决《LinqToSQl和成员访问在类型异常上不合法》经验,为你挑选了2个好方法。

基本问题......

我有一个执行以下代码的方法:

IList 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 WithArtist(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 IQueryable 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(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.Nullable EndDate
    {
        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 IList 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;
        }
    }




}

}



1> Frans Bouma..:

我认为问题是GetGigs中的'let'语句.使用'let'意味着您将最终查询的一部分与要获取的主集分开定义.问题是'let',如果它不是标量,会导致嵌套查询.嵌套查询并不是Linq到sql的最强点,因为它们也被延迟执行.在查询中,将嵌套查询的结果放入要返回的主集的投影中,然后进一步附加linq运算符.

当发生这种情况时,嵌套查询会深入隐藏在将要执行的查询中,这会导致嵌套查询不在要执行的查询的外部投影中,因此必须合并到SQL查询中跑进了数据库.这是不可行的,因为它是嵌套在主sql查询中的投影中的嵌套查询,并且SQL没有像'投影中的嵌套查询'这样的概念,因为你无法在投影中获取一组元素. SQL,只有标量.



2> jpierson..:

我遇到了同样的问题,似乎对我来说诀窍是分离出一个返回IQueryable <>的内联静态方法调用,以便将这个延迟查询存储到一个变量中并引用它.

我认为这是Linq to SQL中的一个错误,但至少有一个合理的解决方法.我还没有对此进行测试,但我的假设是,只有在查询表达式中引用不同类的静态方法时才会出现此问题,无论该函数的返回类型是否为IQueryable <>.所以也许它是持有方法的类,它是问题的根源.就像我说的那样,我无法证实这一点,但可能值得研究.

更新:如果解决方案不清楚,我想在原始帖子的示例的上下文中指出它.

public IQueryable 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(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 
               }

           };
}

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


我刚遇到这个问题,并通过谷歌找到了我自己提出的解决方案,这再一次解决了我遇到的问题.我希望我能说这是我第一次在StackOverflow上做到这一点.
推荐阅读
手机用户2402851335
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有