2012-10-03 35 views
8

Me gustaría utilizar Entity-Framework 5.0 como un asignador O/R con una base de datos PostgreSql. Ya leí muchos HowTos pero aún estoy atascado. Tal vez no entiendo toda la idea detrás de EF.Entity-Framework 5.0 con PostgreSQL

lo que quiero:

  • Quiero escribir el código por mi cuenta. Luego, agregue algunos atributos a las propiedades y clases para decirle al EF cómo mapear los objetos (como haría con NHibernate).
  • No quiero generar una base de datos de mi modelo; solo quiero usar una existente.

Modelo de ejemplo:

[Table("device")] 
public class Device 
{ 
    [Key] 
    public int Id { get; set; } 

    [StringLength(255)] 
    public string Identifier { get; set; } 
} 

[Table("customer")] 
public class Customer 
{ 
    public Customer() 
    { 
     this.Devices = new List<Device>(); 
    } 

    [Key] 
    public int Id { get; set; } 

    [StringLength(255)] 
    public string Name { get; set; } 

    // attribute required? 
    public List<Device> Devices { get; set; } 
} 

Lo que hice:

  • escribió el código anterior
  • creado una clase DatabaseContext
  • Agregado DbProviderFactories y connectionStrings en º e app.config
  • generada ssdl, MSL, archivos CSDL con la herramienta EdmGen.exe y copiarlos en el proyecto (estos archivos están disponibles en la carpeta bin)

DatabaseContext:

public class DatabaseContext : DbContext 
{ 
    static DatabaseContext() 
    { 
     Database.SetInitializer<DatabaseContext>(null); 
    } 

    public DatabaseContext() 
     : base("PostgreSQL") 
    { 

    } 

    public DbSet<Customer> Customers { get; set; } 
    public DbSet<Device> Devices { get; set; } 
} 

app.config:

<?xml version="1.0" encoding="utf-8"?> 
<configuration> 
    <configSections> 
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --> 
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> 
    </configSections> 
    <startup> 
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> 
    </startup> 

    <system.data> 
    <DbProviderFactories> 
     <remove invariant="Npgsql" /> 
     <add name="Npgsql Data Provider" invariant="Npgsql" support="FF" description=".Net Framework Data Provider for Postgresql Server" type="Npgsql.NpgsqlFactory, Npgsql, Version=2.0.12.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7" /> 
    </DbProviderFactories> 
    </system.data> 

    <connectionStrings> 
    <add name="PostGreSQL" 
     providerName="System.Data.EntityClient" 
     connectionString="metadata=.;provider=Npgsql;provider connection string=&quot;Server=asdf;Port=5432;User Id=asdf;Password=asdf;Database=asdf;enlist=true&quot;" /> 
    </connectionStrings> 

</configuration> 

prueba:

using (DatabaseContext context = new DatabaseContext()) 
{ 
    if (context.Database.Exists()) 
    { 
     Console.WriteLine("yep"); 
    } 
    else 
    { 
     Console.WriteLine("nope"); 
    } 

    foreach (Customer c in context.Customers) 
    { 
     Console.WriteLine("Name={0}", c.Name); 
    } 
} 

Console.ReadLine(); 

& salida de error:

"sip" .. lo que significa que la base de datos existe. Pero cuando se accede a la propiedad context.Customers me sale el siguiente excepción:

The entity type Customer is not part of the model for the current context. 

StackTrace:

at System.Data.Entity.Internal.InternalContext.UpdateEntitySetMappingsForType(Type entityType) 
    at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) 
    at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize() 
    at System.Data.Entity.Internal.Linq.InternalSet`1.GetEnumerator() 
    at System.Data.Entity.Infrastructure.DbQuery`1.System.Collections.Generic.IEnumerable<TResult>.GetEnumerator() 
    at EF5.Program.Main(String[] args) in c:\Users\tba\Documents\Visual Studio 2012\Projects\EF5\EF5\Program.cs:line 26 
    at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) 
    at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) 
    at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 
    at System.Threading.ThreadHelper.ThreadStart_Context(Object state) 
    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
    at System.Threading.ThreadHelper.ThreadStart() 

Lo que no entienden:

  • ¿Cuáles son los archivos ssdl, msl, csdl sirven para, si DataAnnoations están disponibles?
  • ¿Por qué la clase Cliente no forma parte del modelo para el contexto actual?

Al usar la herramienta EdmGen.exe, genera también un archivo ObjectLayer.cs que contiene un ObjectContext y clases de entidad.El problema con eso es que las clases de entidad derivan de EntityObject. Si quiero usar las clases de entidad como clases de negocios, este es un problema serio, porque las clases no pueden derivarse de ninguna otra clase.

Además, no entiendo por qué genera un ObjectContext ... cada HowTo que uso utiliza la clase DbContext.

Entidad clase Cliente generado por la herramienta EdmGen:

/// <summary> 
/// No Metadata Documentation available. 
/// </summary> 
[EdmEntityTypeAttribute(NamespaceName="EF5", Name="Customer")] 
[Serializable()] 
[DataContractAttribute(IsReference=true)] 
public partial class Customer : EntityObject 

Estoy confundido :-)

Editar:

  • no estoy usando los ObjectLayer.cs ¡archivo! Y tampoco quiero usarlo, debido a los problemas de herencia que mencioné anteriormente. La clase parcial de clientes es solo un ejemplo para mostrar lo que genera la herramienta EdmGen.
  • Cuando quito el CSDL, MSL y archivos SSDL me sale el siguiente error:

    At least one SSDL artifact is required for creating StoreItemCollection. 
    
  • Cuando quito la palabra clave metadatos de la propiedad ConnectionString en el app.config me sale el siguiente error:

    Some required information is missing from the connection string. The 'metadata' keyword is always required. 
    



Solución:

Finalmente descubrí cómo funciona. ConnectionString en app.config es incorrecto El connectionString correcta:

<connectionStrings> 
    <add name="PostgreSQL" 
     connectionString="Server=asdf;Port=5432;User Id=asdf;Password=asdf;Database=asdf;" 
     providerName="Npgsql" /> 
</connectionStrings> 

que elimina los metadatos, el proveedor y la propiedad de cadena de conexión del proveedor de la connectionString. Como dijo Brice, los archivos de metadatos no son necesarios, así que simplemente los eliminé.

También el atributo de tabla para el dispositivo y la clase del cliente necesita especificar el esquema . De esta manera:

[Table("customer", Schema="public")] 
public class Customer 
+1

Parece que está intentando mezclar los flujos de trabajo modelo primero y Code First. Consulte algunos de los videos de Introducción en [http://msdn.com/data/ef](http://msdn.microsoft.com/en-us/data/ee712907) para obtener más información sobre el uso de EF. – bricelam

+1

Un simple ejemplo sería genial. Un proyecto que utiliza EF5 con una base de datos PostgreSql. Sin ningún diseñador, solo código (código atribuido). – bakunin

+2

Hecho: [Entity Framework en PostgreSQL] (http://brice-lambson.blogspot.com/2012/10/entity-framework-on-postgresql.html) – bricelam

Respuesta

4

No debería estar generando los archivos ssdl, msl, csdl. Estos archivos solo son necesarios si desea usar el diseñador. Elimine estos archivos y ObjectLayer.cs generado.

Tampoco debería utilizar una cadena de conexión EntityClient. Actualice su cadena de conexión para que sea simplemente la siguiente.

<connectionStrings> 
    <add name="PostGreSQL" 
     providerName="Npgsql" 
     connectionString="Server=asdf;Port=5432;User Id=asdf;Password=asdf;Database=asdf;enlist=true" /> 
</connectionStrings> 
+0

Ver mi publicación editada.No uso el archivo ObjectLayer.cs. – bakunin

+0

Actualizado mi respuesta. Parece que tu problema es simplemente la cadena de conexión. – bricelam

+0

Doh, parece que lo tienes funcionando. :) Bien hecho – bricelam

Cuestiones relacionadas