Código EF 4 Primero - Combina Vistas y Tablas

Investigué esta pregunta durante días y parece que no puedo encontrar una opción que me haga sentir bien; sin embargo, aquí hay un enlace a una pregunta muy similar:

Añadir campo calculado al modelo

En última instancia, tengo la misma pregunta, pero espero una solución mejor.

Considere las siguientes tablas DB:

<code>CREATE TABLE [Contact](
[ContactID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[ContactName] [varchar](80) NOT NULL,
[Email] [varchar](80) NOT NULL,
[Title] [varchar](120) NOT NULL,
[Address1] [varchar](80) NOT NULL,
[Address2] [varchar](80) NOT NULL,
[City] [varchar](80) NOT NULL,
[State_Province] [varchar](50) NOT NULL,
[ZIP_PostalCode] [varchar](30) NOT NULL,
[Country] [varchar](50) NOT NULL,
[OfficePhone] [varchar](30) NOT NULL,
[MobilePhone] [varchar](30) NOT NULL)

CREATE TABLE [Blog](
[BlogID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[BlogName] [varchar](80) NOT NULL,
    [CreatedByID] [int] NOT NULL,  -- FK to ContactTable
    [ModifiedByID] [int] NOT NULL  -- FK to ContactTable
)

CREATE TABLE [Post](
[PostID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
    [BlogID] [int] NOT NULL, -- FK to BlogTable
[Entry] [varchar](8000) NOT NULL,
    [CreatedByID] [int] NOT NULL,  -- FK to ContactTable
    [ModifiedByID] [int] NOT NULL  -- FK to ContactTable
)
</code>

Ahora me gustaría usar vistas para cargar información de búsqueda / calculada "común". Cada vez que mostramos una publicación en el sitio, queremos saber el nombre de la persona que creó la publicación y quién la modificó por última vez. Estos son dos campos que se almacenan en tablas separadas de la tabla de publicaciones. Podría usar fácilmente la siguiente sintaxis (asumiendo que la carga perezosa / ansiosa se aplicó y CreatedBy era una propiedad, de tipo Contacto, basada en CreatedByID): currentPost.CreatedBy.Name;

El problema con ese enfoque es la cantidad de llamadas Db y también el gran registro recuperado para el contacto, pero solo estamos usando Nombre 99% en esta situación. Me doy cuenta de que el esquema de DB anterior es pequeño, pero este es solo un ejemplo simplificado y la tabla de contactos real tiene aproximadamente 50 campos.

Para administrar este tipo de situación en el pasado (antes de usar EF), normalmente he creado vistas de "detalle" para las tablas que usaré. Las vistas "detalladas" contienen campos comunes de búsqueda / cálculo, de modo que solo se necesita una llamada a la base de datos para obtener de manera eficiente toda la información que necesito (NOTA: También utilizamos la indexación en nuestras vistas SQL para que sea extremadamente eficiente para la lectura) Aquí está una lista de vistas que usaré comúnmente (ya que contendrán campos de "búsqueda" de tablas relacionadas):

<code>ALTER VIEW [icoprod].[BlogDetail]
AS
SELECT  B.[BlogID], 
    B.[BlogName], 
    B.[BlogDescription],
    B.[CreatedByID], 
    B.[ModifiedByID],
    CREATEDBY.[ContactName] AS CreatedByName, 
    MODIFIEDBY.[ContactName] AS ModifiedByName,
    (SELECT COUNT(*) FROM Post P WHERE P.BlogID = B.BlogID) AS PostCount
FROM    Blog AS B 
JOIN Contact AS CREATEDBY ON B.CreatedByID = CREATEDBY.ContactID 
JOIN Contact AS MODIFIEDBY ON B.ModifiedByID = MODIFIEDBY.ContactID

ALTER VIEW [icoprod].[PostDetail]
AS
SELECT  P.[PostID], 
    P.[BlogID],
    P.[Entry], 
    P.[CreatedByID], 
    P.[ModifiedByID],
    CREATEDBY.[ContactName] AS CreatedByName, 
    MODIFIEDBY.[ContactName] AS ModifiedByName,
    B.Name AS BlogName
FROM    Post AS P
JOIN Contact AS CREATEDBY ON P.CreatedByID = CREATEDBY.ContactID 
JOIN Contact AS MODIFIEDBY ON P.ModifiedByID = MODIFIEDBY.ContactID
JOIN Blog AS B ON B.BlogID = P.BlogID
</code>

Aquí hay una visión general de mis objetos "POCO":

<code>public class Blog
{
    public int ID { get; set; }
    public string Name { get; set; }

    public int CreatedByID { get; set; }
    public DateTime ModifiedByID { get; set; }
}

public class Post
{
    public int ID { get; set; }
    public string Name { get; set; }

    public int CreatedByID { get; set; }
    public DateTime ModifiedByID { get; set; }
}

public class Contact
{
    public int ID { get; set; }
    public string Name { get; set; }

    public string Email { get; set; }
    public string Title { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public string MobilePhone { get; set; }
}

public class BlogDetails : Blog
{
    public string CreatedByName { get; set; }
    public string ModifiedByName { get; set; }
    public int PostsCount { get; set; }
}

public class PostDetails : Post
{
    public string CreatedByName { get; set; }
    public string ModifiedByName { get; set; }
    public string BlogName { get; set; }
}
</code>

La razón por la que me gusta este enfoque es que me permite recuperar información de la base de datos basada en tablas o vistas Y si carga una vista, la vista contiene toda la información de la "tabla" que me permitiría cargar desde una vista pero guardar en una mesa. OMI, esto me da lo mejor de ambos mundos.

He utilizado este enfoque en el pasado, pero, por lo general, simplemente cargué información de la base de datos utilizando datos de datos o datos de procesos almacenados o incluso utilicé patrones subsónicos de registro de activista y campos asignados después de cargarlos desde la base de datos. Realmente espero poder hacer algo en EF que me permita cargar estos objetos sin crear otra capa de abstracción.

Esto es lo que he intentado usar para la configuración (usando Fluent API y el código primero EF):

<code>public class PostConfiguration : EntityTypeConfiguration<Post>
{
    public PostConfiguration()
        : base()
    {
        HasKey(obj => obj.ID);

        Property(obj => obj.ID).
            HasColumnName("PostID").
            HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).
            IsRequired();

        Map(m =>
            {
                m.ToTable("Post");
            });
    }
}

public class BlogConfiguration : EntityTypeConfiguration<Blog>
{
    public BlogConfiguration()
        : base()
    {
        HasKey(obj => obj.ID);

        Property(obj => obj.ID).
            HasColumnName("BlogID").
            HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).
            IsRequired();

        Map(m =>
            {
                m.ToTable("Blog");
            });
    }
}

public class ContactConfiguration : EntityTypeConfiguration<Contact>
{
    public ContactConfiguration()
        : base()
    {
        HasKey(obj => obj.ID);

        Property(obj => obj.ID).
            HasColumnName("ContactID").
            HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).
            IsRequired();

        Map(m =>
            {
                m.ToTable("Contact");
            });
    }
}

public class PostDetailsConfiguration : EntityTypeConfiguration<PostDetails>
{

    public PostDetailsConfiguration()
        : base()
    {

        Map(m =>
            {
                m.MapInheritedProperties();
                m.ToTable("icoprod.PostDetails");
            });

    }

}

public class BlogDetailsConfiguration : EntityTypeConfiguration<BlogDetails>
{

    public BlogDetailsConfiguration()
        : base()
    {

        Map(m =>
            {
                m.MapInheritedProperties();  
                m.ToTable("icoprod.BlogDetails");
            });

    }

}
</code>

En este punto, he intentado usar una vista que contiene toda la información de la tabla con información "extendida" y cuando intento esto obtengo el error 3032 temido (muestra de error aquí). Luego traté de que la vista SOLAMENTE contenga la clave principal de la tabla y las propiedades "extendidas" (por ejemplo, [Entrada] no está en la vista PostDetails). Cuando intento esto, me sale el siguiente error:

<code>All objects in the EntitySet 'DBContext.Post' must have unique primary keys. However, an instance of type 'PostDetails' and an instance of type 'Post' both have the same primary key value, 'EntitySet=Post;ID=1'.
</code>

Así que he jugado dejando de lado MapInheritedProperties un poco, pero sin suerte. Sigo recibiendo un error similar.

¿Alguien tiene alguna sugerencia sobre cómo "extender" un objeto de base / tabla y cargar información desde una vista? Una vez más, creo que hay una gran ganancia de rendimiento al hacer esto. El artículo al que hice referencia al principio de esta pregunta tiene 2 soluciones potenciales, pero 1 requiere demasiados accesos a la base de datos (solo para obtener información de búsqueda común) y el otro requiere una capa adicional de abstracción (y realmente me gustaría ir directamente a mis POCO's de la base de datos, sin escribir ningún mapeo).

Por último,gracias a todos los que responden a este tipo de preguntas. Aplaudo a todos los que han contribuido a las respuestas a lo largo de los años. Creo que muchos de los desarrolladores tomamos esta información por sentado!

Respuestas a la pregunta(1)

Su respuesta a la pregunta