¿Pueden estos modelos estar representados en EF7?

c# entity-framework-core

Pregunta

Estoy tratando de usar algunas clases de otro conjunto en mi propio proyecto como entidades en las que puedo persistir usando EF7, en lugar de escribir una serie de clases muy similares que sean más amigables con la base de datos.

Las versiones simplificadas se ven así:

interface IMediaFile
{
    string Uri { get; }
    string Title { get; set; }
}
class CMediaFile : IMediaFile
{
    public CMediaFile() { }
    public string Uri { get; set; }
    public string Title { get; set; }
}

//The following types are in my project and have full control over.
interface IPlaylistEntry
{
    IMediaFile MediaFile { get; }
}
class CPlaylistEntry<T> : IPlaylistEntry where T : IMediaFile
{
    public CPlaylistEntry() { }
    public T MediaFile { get; set; }
}

Hay múltiples implementaciones de IMediaFile, estoy mostrando solo una. Mi clase PlaylistEntry toma un argumento genérico para habilitar diferentes características para esas diversas implementaciones, y solo trabajo con IPlaylistEntry.

Así que he empezado a modelarlo así:

interface IMediaFile
{
    string Uri { get; }
    string Title { get; set; }
}
class CMediaFile : IMediaFile
{
    public CMediaFile() { }
    public string Uri { get; set; }
    public string Title { get; set; }
}

//The following types are in my project and have full control over.
interface IPlaylistEntry
{
    IMediaFile MediaFile { get; }
}
class CPlaylistEntry<T> : IPlaylistEntry where T : IMediaFile
{
    public CPlaylistEntry() { }
    public T MediaFile { get; set; }
}

Como prueba simple, ignoro CPlaylistEntry <> y simplemente hago:

interface IMediaFile
{
    string Uri { get; }
    string Title { get; set; }
}
class CMediaFile : IMediaFile
{
    public CMediaFile() { }
    public string Uri { get; set; }
    public string Title { get; set; }
}

//The following types are in my project and have full control over.
interface IPlaylistEntry
{
    IMediaFile MediaFile { get; }
}
class CPlaylistEntry<T> : IPlaylistEntry where T : IMediaFile
{
    public CPlaylistEntry() { }
    public T MediaFile { get; set; }
}

Esto arroja:

NotSupportedException: el 'MediaFile' en el tipo de entidad 'CPlaylistEntry' no tiene un conjunto de valores y no hay ningún generador de valores disponible para las propiedades de tipo 'CMediaFile'. Establezca un valor para la propiedad antes de agregar la entidad o configure un generador de valores para las propiedades del tipo 'CMediaFile'`

Ni siquiera entiendo esta excepción, y no veo por qué aparece CPlaylistEntry cuando solo estoy tratando de almacenar una entidad CMediaFile. Supongo que esto está relacionado con la definición de mi modelo, específicamente la definición de la clave principal de CPlaylistEntry como no es un tipo simple, sino un tipo complejo, otra entidad. Sin embargo, espero que EF sea lo suficientemente inteligente como para entender que todo se reduce a una cadena Uri, porque ese tipo complejo ya tiene su propia clave primaria declarada, y he declarado la propiedad como una clave externa para ese tipo.

¿Es posible modelar estas clases en EF sin rediseñarlas radicalmente para mirar más de cerca lo que podrían ser las tablas de base de datos correspondientes? Trabajé con la base de datos de EF6 primero en el pasado, así que este es mi primer intento en un patrón de código primero, y realmente espero poder aislar el desorden en el que una base de datos podría tener el aspecto de mi definición de modelo, y mantengo las clases "limpias" con las que interactúo en .NET.

Si se requiere más explicación de estos tipos y su relación, solo pregunte: estoy intentando mantener esto breve.

Respuesta aceptada

Duda que esto sea compatible actualmente (no estoy seguro si eventualmente lo hará o no). He intentado recrear su modelo con ligeros cambios y al intentar crear la base de datos obtengo:

System.NotSupportedException: la propiedad 'PlaylistEntry`1MediaFile' no se puede asignar porque es del tipo 'MediaFile', que actualmente no es compatible.

Actualización 1

Creo que el hecho de que esté poniendo MediaFile como clave está creando problemas. He hecho algunos cambios a tu modelo. Espero que esto no rompa nada negativo en su final:

public interface IPlaylistEntry<T>
    where T : IMediaFile
{
    T MediaFile { get; set; }
}

public class PlaylistEntry<T> : IPlaylistEntry<T>
    where T : IMediaFile
{
    public int Id { get; set; }
    public string PlaylistInfo { get; set; } //added for testing purposes
    public T MediaFile { get; set; }
}

Asignaciones:

public interface IPlaylistEntry<T>
    where T : IMediaFile
{
    T MediaFile { get; set; }
}

public class PlaylistEntry<T> : IPlaylistEntry<T>
    where T : IMediaFile
{
    public int Id { get; set; }
    public string PlaylistInfo { get; set; } //added for testing purposes
    public T MediaFile { get; set; }
}

Uso:

public interface IPlaylistEntry<T>
    where T : IMediaFile
{
    T MediaFile { get; set; }
}

public class PlaylistEntry<T> : IPlaylistEntry<T>
    where T : IMediaFile
{
    public int Id { get; set; }
    public string PlaylistInfo { get; set; } //added for testing purposes
    public T MediaFile { get; set; }
}

Esto funciona y guarda los datos correctos en la base de datos.

Puede recuperar los datos utilizando:

public interface IPlaylistEntry<T>
    where T : IMediaFile
{
    T MediaFile { get; set; }
}

public class PlaylistEntry<T> : IPlaylistEntry<T>
    where T : IMediaFile
{
    public int Id { get; set; }
    public string PlaylistInfo { get; set; } //added for testing purposes
    public T MediaFile { get; set; }
}

Actualización 2

Como no desea tener una identidad como clave, puede agregar una propiedad Uri a su clase de lista de reproducción que se usará para la relación entre PlaylistEntry y MediaFile.

public interface IPlaylistEntry<T>
    where T : IMediaFile
{
    T MediaFile { get; set; }
}

public class PlaylistEntry<T> : IPlaylistEntry<T>
    where T : IMediaFile
{
    public int Id { get; set; }
    public string PlaylistInfo { get; set; } //added for testing purposes
    public T MediaFile { get; set; }
}

Aquí es cómo se vería la asignación en este caso:

public interface IPlaylistEntry<T>
    where T : IMediaFile
{
    T MediaFile { get; set; }
}

public class PlaylistEntry<T> : IPlaylistEntry<T>
    where T : IMediaFile
{
    public int Id { get; set; }
    public string PlaylistInfo { get; set; } //added for testing purposes
    public T MediaFile { get; set; }
}

El uso para insertar datos sigue siendo el mismo:

public interface IPlaylistEntry<T>
    where T : IMediaFile
{
    T MediaFile { get; set; }
}

public class PlaylistEntry<T> : IPlaylistEntry<T>
    where T : IMediaFile
{
    public int Id { get; set; }
    public string PlaylistInfo { get; set; } //added for testing purposes
    public T MediaFile { get; set; }
}

Este código anterior pondrá "irrelevante" en la propiedad Url PlaylistEntry ya que se usa como la clave externa.

Y para recuperar datos:

public interface IPlaylistEntry<T>
    where T : IMediaFile
{
    T MediaFile { get; set; }
}

public class PlaylistEntry<T> : IPlaylistEntry<T>
    where T : IMediaFile
{
    public int Id { get; set; }
    public string PlaylistInfo { get; set; } //added for testing purposes
    public T MediaFile { get; set; }
}

La unión ocurrirá en el campo Uri en ambas tablas.




Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué