La consulta de Entity Framework devuelve un registro, pero se supone que debe devolver más

Como dice el título, tengo un problema con una consulta en Asp.net mvc 3 EF. Tengo 2 tablas con una relación de 1 a muchos.

table1 Usuarios int user_ID string nombre de usuario

table2 Amigos int ID_amistad int ID_usuario int ID_amigo

El controlador:

// // OBTENER: /Usuario/Detalles/5

public ViewResult Details(int id)
    {
        User user = db.Users.Include("Friends").FirstOrDefault(u => u.user_ID == id);
        //Also for each friend get the User:
        foreach (var friend in user.Friends.ToList())
        {
            friend.User = db.Users.Find(friend.friend_ID);
        }
        return View(user);
    }

La vista "detalles":

@model Social2.Models.User

@{
    ViewBag.Title = "Details";
}

<h2>Details</h2>
    <div class="display-field">
        @foreach (var friend in @Model.Friends)
    {
           @friend.User.username;
    }   
    </div>

Antecedentes:

public partial class ASPNETDBEntities : DbContext
{
    public ASPNETDBEntities()
        : base("name=ASPNETDBEntities")
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }

    public DbSet<aspnet_Users> aspnet_Users { get; set; }
    public DbSet<Friend> Friends { get; set; }
    public DbSet<User> Users { get; set; }
}

modelo de usuario:

public partial class User
{
    public User()
    {
        this.Friends = new HashSet<Friend>();
    }
    [Key]
    public int user_ID { get; set; }
    public System.Guid user_UniqueID { get; set; }
    public string username { get; set; }

    public virtual aspnet_Users aspnet_Users { get; set; }
    public virtual ICollection<Friend> Friends { get; set; }
}

amigo modelo

public partial class Friend
{
    public int friendship_ID { get; set; }
    public int user_fr_ID { get; set; }
    public int friend_ID { get; set; }

    public virtual User User { get; set; }
}

El problema es que, cuando voy a ~/usuario/detalles/1, la vista muestra solo un (el último) amigo. Para cada usuario, muestra su último amigo. ¿Cómo mostrarlos todos?

preguntado el 12 de junio de 12 a las 14:06

Por cierto, puedes usar Include("Friends.User") en lugar del bucle. Pero eso no resolverá tu problema. ¿Verificó en la base de datos que realmente tiene varios amigos para el usuario dado? -

Sí, eliminé al último amigo del primer usuario, agregué uno nuevo y ahora lo muestra en la página.. -

Bueno, esto no prueba que tengas varios amigos para un usuario. Quise decir: si tiene un usuario con Id = 5, ¿tiene varios registros en la tabla de amigos que tienen el valor 5 en la columna? user_fr_ID? -

Tengo 4 usuarios y la base de datos se ve así: 1 2 | 1 3 | 2 3 | 1 4 | 3 1 | cada 2 números son una fila -

y estoy buscando un usuario con id 1 -

3 Respuestas

Su base de datos debe tener dos relaciones definidas así:

Esquema de base de datos

Si crea un modelo de entidad a partir de este esquema, también obtiene dos relaciones de uno a muchos. Y cuando aplica la plantilla DBContext T4 a este modelo, debería obtener clases POCO así:

public partial class Users
{
    public Users()
    {
        this.Friends = new HashSet<Friends>();
        this.Friends1 = new HashSet<Friends>();
    }

    public int user_ID { get; set; }
    public string username { get; set; }

    public virtual ICollection<Friends> Friends { get; set; }
    public virtual ICollection<Friends> Friends1 { get; set; }
}

public partial class Friends
{
    public int friendship_ID { get; set; }
    public int user_fr_ID { get; set; }
    public int friend_ID { get; set; }

    public virtual Users Users { get; set; }
    public virtual Users Users1 { get; set; }
}

Users.Friends and Friends.Users formar un par para la primera relación y Users.Friends1 and Friends.Users1 son un par para la segunda relación. (Puede cambiar el nombre de las propiedades de navegación en el diseñador de modelos para que los nombres sean más significativos). Su consulta se vería así (puede incluir un "segundo nivel" y no necesita el ciclo como lo hizo en su ejemplo):

public ViewResult Details(int id)
{
    // important to use User1 in Include, not User
    User user = db.Users.Include("Friends.User1")
        .FirstOrDefault(u => u.user_ID == id);
    return View(user);
}

Contamos con DbContext también puede utilizar la versión fuertemente tipada de Include:

Include(u => u.Friends.Select(f => f.User1))

Respondido el 12 de junio de 12 a las 15:06

Ty por su tiempo y ayuda. Volveré a crear la base de datos. Una cosa más, ¿conoces algún tutorial en línea o algo similar para estas consultas en EF? Me refiero a ".Include()" o ".FirstOrDefault()" y algunas funciones similares. Realmente no sé lo que hacen y realmente quiero aprenderlos. - milanesa

@MilanMilanovski: Aquí hay un tutorial (de 12 partes) sobre DbContext en general: blogs.msdn.com/b/adonet/archive/2011/01/27/…. La parte 6 contiene Include. For FirstOrDefault y así sucesivamente... cualquier tutorial de LINQ está bien. La mayoría de los métodos LINQ funcionan con EF, solo unos pocos no. Vista plural (pluralsight-training.net) también tiene muchos videos de capacitación sobre LINQ y EF. (Su curso LINQ es increíble). Ofrecen una prueba gratuita, por lo que puede probar antes de decidir suscribirse o no. - Slauma

Creo que el problema es el mapeo de la clase Amigo.

intenta cambiar a:

public partial class Friend
{
    [Key]
    public int friendship_ID { get; set; }
    public int user_fr_ID { get; set; }
    public int friend_ID { get; set; }

    [ForeignKey("friend_ID")]
    public virtual User User { get; set; }
}

Respondido el 12 de junio de 12 a las 14:06

¿friend_id es la clave externa? Si no, simplemente cambie el parámetro. - jone polvora

Creo que volveré a crear la base de datos, malditos nombres, no sabía que el nombre + ID debería estar en la misma palabra: milanesa

@MilanMilanovski: ¿Utiliza Model-First o Database-First? Supongo que por el UnintentionalCodeFirstException. En este caso, las anotaciones de datos no tienen ningún efecto porque el mapeo se define en EDMX y no con anotaciones Code-First o Fluent API. - Slauma

Primero uso la base de datos. No me digas que las anotaciones de datos no tienen efecto... paso todo el día tratando de resolver el problema... - milanesa

@MilanMilanovski: No, las anotaciones (para el mapeo EF) no tienen efecto con DB First. Son solo para Code-First. ¿Qué hiciste con el código generado automáticamente por la plantilla DbContext T4? Se supone que no debes cambiar este código en absoluto. ¿Puedes mostrar el código original generado automáticamente antes de cambiarlo? Lo más probable es que las relaciones estén mal... - Slauma

Creo que el problema esta aqui

User user = db.Users.Include("Friends").FirstOrDefault(u => u.user_ID == id);

FirstOrDefault da un solo registro.

Respondido el 12 de junio de 12 a las 14:06

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.