2009-02-07 7 views
10

El problema básico ...LinqToSql y el Miembro no acceso legal del tipo de excepción

tengo un método que ejecuta el siguiente código:

IList<Gig> gigs = GetGigs().WithArtist(artistId).ToList(); 

Los GetGigs() método obtiene Gigs de mi base de datos a través de LinqToSql ...

lo tanto, cuando GetGigs() WithArtist (ArtistaID) .ToList() se ejecuta consigo la siguiente excepción:.

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] 

Tenga en cuenta que la función de extensión "WithArtist" se parece a esto:

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

Si sustituyo las GetGigs método() con un método que construye una colección de conciertos en código (en lugar de la base de datos a través de LinqToSql) NO tengo la excepción.

Así que estoy bastante seguro de que el problema es con mi código LinqToSQl en lugar de la estructura del objeto.

Sin embargo, no tengo IDEA por qué la versión de LinqToSQl no funciona, por lo que he incluido todo el código asociado a continuación. Cualquier ayuda sería MUY agradecida recibida !!

El código 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); 
    } 

he incluido el código de la Ley, del artista y del carruaje objetos continuación:

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

Me encuentro con este mismo error y en mi caso parece estar relacionado con el uso de una subconsulta correlacionada dentro de mi cláusula WHERE. Si encuentro alguna información, le daré una actualización. – jpierson

Respuesta

1

no veo cualquier cosa en sus clases para indicar cómo se define LINQ to SQL para determinar qué columna es cuál, etc.

W ¿Espera que el método WithArtist se ejecute en .NET o se convierta en SQL? Si espera que se convierta en SQL, deberá decorar su clase Gig con los atributos LINQ to SQL adecuados (o configurar su contexto de datos de otra manera). Si desea que se ejecute en código, simplemente cambie el primer tipo de parámetro de IQueryable<Gig> a IEnumerable<Gig>.

+0

Hay clases de gig generadas de forma automática de LinqToSQL. La clase de concierto definida anteriormente son objetos de esquema que estoy adaptando a LinqToSQl Data en ... – iasksillyquestions

+0

¿El tipo de Gig que está volviendo de GetGigs() que LINQ to SQL sabe o no tiene? –

+0

@Jon: Sé que estás ocupado (y esta pregunta es bastante antigua, ahora), pero ¿hay alguna posibilidad de que puedas explicar tu respuesta con algún código ... con un énfasis en * convertir a SQL *, ángulo. Tengo exactamente el mismo problema aquí. Estoy usando el patrón Repository (por ejemplo, GetActs()) + Pipes and Filters (por ejemplo, con Artist()) y mi repositorio no maneja otras propiedades * children * (por ejemplo, Gigs es parent, la propiedad Acts es child) , así que estaba tratando de manipular la consulta (por ejemplo, WithActs()) para devolver dinámicamente un niño asignado, si el consumidor codifica para eso. Este problema me está matando :( –

4

Creo que el problema es la declaración 'let' en GetGigs. El uso de 'let' significa que usted define una parte de la consulta final por separado desde el conjunto principal a buscar. el problema es que 'let', si no es un escalar, da como resultado una consulta anidada. Las consultas anidadas no son realmente Linq al punto más fuerte de sql ya que también se ejecutan diferidas. En su consulta, coloca los resultados de la consulta anidada en la proyección del conjunto principal para devolver, que luego se agrega con operadores linq.

Cuando ESO sucede, la consulta anidada se oculta más profundamente en la consulta que se ejecutará, y esto lleva a una situación en la que la consulta anidada no está en la proyección externa de la consulta para ejecutarse y debe fusionarse en la consulta SQL se ejecutó en la base de datos. Esto no es factible, ya que es una consulta anidada en una proyección anidada dentro de la consulta SQL principal y SQL no tiene un concepto como 'consulta anidada en una proyección', ya que no se puede obtener un conjunto de elementos dentro de una proyección en SQL, solo escalares.

+0

Entonces, ¿cómo cargo una colección de actos sin usar let? – iasksillyquestions

+0

Muchas gracias por su ayuda por cierto! – iasksillyquestions

+0

Puede usarlo de la forma en que lo hace, pero luego no puede agregar operadores de consulta a esa consulta: la consulta anidada debe estar en la proyección externa. Entonces, la consulta de GetGigs se ejecutará con la consulta anidada. –

5

Tuve el mismo problema y lo que pareció hacer el truco para mí fue separar una llamada al método estático en línea que devolvió IQueryable <> para que almacenara esta consulta diferida en una variable y se hiciera referencia a eso.

Creo que esto es un error en Linq a SQL, pero al menos hay una solución razonable. No he probado esto todavía, pero mi hipótesis es que este problema puede surgir solo cuando se hace referencia a métodos estáticos de una clase diferente dentro de una expresión de consulta independientemente de si el tipo de devolución de esa función es IQueryable <>. Entonces, tal vez sea la clase la que tenga el método que está en la raíz del problema. Como dije, no he podido confirmar esto pero puede valer la pena investigarlo.

ACTUALIZACIÓN: Por si la solución no es clara, quería señalarlo en el contexto del ejemplo de la publicación original.

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 
       } 

      }; 
} 

Tenga en cuenta que si bien esto debería corregir el problema en cuestión no parece ser también otro problema en esa consulta los actos diferidos está siendo visitada en cada elemento de la proyección que yo supongo que causaría consultas separadas que se publicará a la base de datos por fila en la proyección exterior.

+1

Muchas gracias, tuve el mismo problema y ponerlo en una variable realmente resuelve el problema. Y estoy de acuerdo, parece un error en Linq a SQL. – Magnus

+1

Establecí puntos de interrupción en mis métodos de extensión mientras se depuraba esto y ni siquiera recibían un golpe. Después de crear una variable para el método de extensión, parte de mi consulta funcionó y los puntos de interrupción se vieron afectados. –

+3

Acabo de toparme con este problema y encontré mi propia solución propuesta a través de google, que una vez más resolvió el problema que estaba teniendo. Ojalá pudiera decir que es la primera vez que hago eso en StackOverflow. – jpierson

Cuestiones relacionadas