2011-06-28 10 views
18

En general, tiendo a nombrar mis columnas de base de datos SQL utilizando la siguiente convención caso de camellos:Entity Framework - Aprovechando nombre de propiedad de primera letra

camelCase (nótese que la primera letra está en minúscula).

Pero cuando se trabaja con C#, me gustaría nombrar las propiedades públicas de mi objeto en la siguiente convención:

CamelCase (nótese el primero es en el caso uppwer).

El comportamiento predeterminado de Entity Framework es nombrar las propiedades de las clases creadas para que coincidan con sus nombres de columna relativos tal como están en la base de datos.

¿Hay alguna propiedad en el nivel de proyecto/solución que pueda cambiarse para resolver este problema?

+0

¿Es dbFirst approch ryt? –

+0

He intentado cambiar el nombre de las tablas en el diseñador de modelos de datos de entidad ADO.NET (haga doble clic en el archivo .edmx) pero si cambio el nombre de las tablas allí, entonces los métodos también cambian de nombre. Por ejemplo, si cambio el nombre de la tabla 'cliente' por' Cliente', entonces el método 'AddTocustomers' se renombra a' AddToCustomers1' ¿por qué visual studio coloca un 1? –

+0

¿Necesita modificar únicamente los nombres de propiedad ryt? –

Respuesta

3

I no sabe de un nivel de la solución, pero se puede establecer un atributo de su entidad

[Table("myEntity")] 
public class MyEntity{} 
+0

Gracias, aunque estoy buscando algo que afectará a todo el modelo, ya que es una molestia ir a través de todo el conjunto de propiedades para cada clase. –

0

Puede cambiarlo en el archivo .edmx. Simplemente haga clic en el nombre de la propiedad y cámbiele el nombre a camel case y lo mismo se reflejará cada vez que intente acceder utilizando el objeto.

+3

Gracias, aunque estoy buscando algo que afectará a todo el modelo, ya que es una molestia ir a través de todo el conjunto de propiedades para cada clase. –

2

Lograr esto no es imposible, pero no será fácil. Algunos de ellos dependen del tipo de modelo con el que se trabaja, primero el código o la base de datos/modelo (son similares a este respecto), o si está utilizando los métodos antiguos basados ​​en ObjectContext.

En general, EF usa plantillas T4 para crear las clases y modelos reales en todos los códigos, excepto en primer lugar, por lo que es posible editar las plantillas T4 y generar lo que desee, como generar propiedades automáticamente con PascalCasing.

Si primero está utilizando el código (que realmente no requiere que codifique primero, es un nombre terrible) entonces puede usar las herramientas eléctricas de Entity Framework para aplicar ingeniería inversa a su base de datos para codificar los primeros modelos, y nuevamente usa T4 para hacer esto.

Si está utilizando el código real primero (es decir, crea sus modelos y genera su base de datos a partir del modelo), entonces puede que no sea posible en el EF5 existente o inferior. EF6 (actualmente en alfa) tiene algo conocido como convenciones personalizadas que probablemente pueda usar para esto, pero todavía está muy lejos de la calidad de producción.

0

Puede utilizar herramientas externas como http://www.devart.com/entitydeveloper/

Con la inbuild desinger EDMX esto no es posible, ya que la "actualización de la base de datos" duerma rutina de tener una función de este tipo.

0

El código de clase se genera a partir de una plantilla T4. Dependiendo de su configuración, esto puede estar ya en su proyecto, o el EDMX puede estar usando un integrado, en cuyo caso necesitaría agregar el suyo y establecer la "estrategia de generación de código" en "Ninguno" en el EDMX propiedades (a través del navegador modelo). A partir de este archivo, es bastante fácil encontrar y modificar la generación del nombre de clase y propiedad.

El valor por defecto está llamando a una función Escape, que se define en los archivos de inclusión en "IDE/Extensiones/Herramientas/Framework Microsoft Entidad/Plantillas/Incluye" bajo la carpeta de Visual Studio, y en última instancia, sólo llama CreateEscapedIdentifier. Simplemente llame a esto con la versión en mayúscula de la cadena.

FYI: Estos nombres proceden de los objetos EntityType y NavigationProperty tal como se definen en el EDMX, no directamente de la base de datos. Si está utilizando la función "generar desde la base de datos" para el EDMX, es posible que los nombres ya hayan pasado por una transformación y que los nombres originales de la tabla no se conserven en el modelo. Sin embargo, esto probablemente no sea un problema.

1

Anteriormente también tuve ese tipo de problema. Así que simplemente escribo una herramienta en C# para cambiar el nombre del archivo edmx existente y luego, después de cambiar el nombre de cada sección del archivo edmx, el siguiente uso de la plantilla T4 regenera las clases Poco. Resolvió mi problema Genera las clases de POCO esperadas con las propiedades de Camel Case. Básicamente en el edmx tenemos 3 capas. Entonces tenemos que modificar 2 capas de ellos.

  • MappingsSection
  • ConceptualModelsSection

Por favor, encontrar la siguiente clase para hacer eso.

namespace Edmx_Manager_V1._0 
{ 
    using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Xml; 

    public static class RenameManager 
    { 
     public static XmlDocument Document = new XmlDocument(); 
     public static string FilePath; 
     public static XmlNamespaceManager nsmgr; 

     /// <summary> 
     /// Updates the conceptual models section. 
     /// </summary> 
     public static void UpdateConceptualModelsSection() 
     { 

      ///////////////////////update ConceptualModels section////////////////////////////////////////////////////////// 

      XmlNodeList Schema = Document.SelectNodes("/edmx:Edmx/edmx:Runtime/edmx:ConceptualModels/edm:Schema", nsmgr); 

      XmlNode SchemaNode = Schema[0]; 
      XmlElement SchemaNodeXmlElement = SchemaNode as XmlElement; 

      //get all EntitySet nodes under EntityContainer node 
      XmlNodeList EntitySetlist = SchemaNodeXmlElement.GetElementsByTagName("EntitySet"); 

      //get all EntityType nodes under SchemaNode 
      XmlNodeList EntityTypelist = SchemaNodeXmlElement.GetElementsByTagName("EntityType"); 

      foreach (XmlNode EntityTypenode in EntityTypelist) 
      { 

       //to call GetElementsByTagName we need XmlElement object 
       XmlElement EntityTypenodeelement = EntityTypenode as XmlElement; 

       //get all PropertyRef nodes under EntityType node 
       XmlNodeList PropertyReflist = EntityTypenodeelement.GetElementsByTagName("PropertyRef"); 

       foreach (XmlNode PropertyRefnode in PropertyReflist) 
       { 
        //update name attribute of Key/PropertyRef nodes 
        XmlAttribute PropertyRef_nameAttribute = PropertyRefnode.Attributes["Name"]; 
        PropertyRef_nameAttribute.Value = UppercaseFirst(PropertyRef_nameAttribute.Value); 
       } 

       //get all Property nodes under EntityType node 
       XmlNodeList Propertylist = EntityTypenodeelement.GetElementsByTagName("Property"); 

       foreach (XmlNode Propertynode in Propertylist) 
       { 
        //update name attribute of PropertyRef nodes 
        XmlAttribute Property_nameAttribute = Propertynode.Attributes["Name"]; 
        Property_nameAttribute.Value = UppercaseFirst(Property_nameAttribute.Value); 
       } 

       //get all NavigationProperty nodes under EntityType node 
       XmlNodeList NavigationPropertylist = EntityTypenodeelement.GetElementsByTagName("NavigationProperty"); 

       foreach (XmlNode NavigationPropertynode in NavigationPropertylist) 
       { 
        //update name attribute of NavigationProperty nodes 
        XmlAttribute NavigationPropertynode_nameAttribute = NavigationPropertynode.Attributes["Name"]; 
        NavigationPropertynode_nameAttribute.Value = UppercaseFirst(NavigationPropertynode_nameAttribute.Value) + "s";// we append "s" for nav properties 
       } 
      } 

      //get Association node under Schema node 
      XmlNodeList Associationlist = SchemaNodeXmlElement.GetElementsByTagName("Association"); 

      //get all Association nodes and process 
      foreach (XmlNode AssociationNode in Associationlist) 
      { 
       if (AssociationNode != null) 
       { 
        XmlElement AssociationNodeXmlElement = AssociationNode as XmlElement; 
        //get all end nodes under Association 
        XmlNodeList EndNodelist2 = AssociationNodeXmlElement.GetElementsByTagName("End"); 

        //get all PropertyRef nodes under Association 
        XmlNodeList PropertyReflist2 = AssociationNodeXmlElement.GetElementsByTagName("PropertyRef"); 

        foreach (XmlNode PropertyRefNode2 in PropertyReflist2) 
        { 
         //update Type attribute 
         XmlAttribute PropertyRefNode2Attribute = PropertyRefNode2.Attributes["Name"]; 
         PropertyRefNode2Attribute.Value = UppercaseFirst(PropertyRefNode2Attribute.Value); 
        } 
       } 
      } 

      Console.WriteLine("ConceptualModelSection updated.."); 
     } 

     /// <summary> 
     /// Updates the mappings section. 
     /// </summary> 
     public static void UpdateMappingsSection() 
     { 

      ///////////////////////update edmx:Mappings section////////////////////////////////////////////////////////// 

      XmlNodeList EntityContainerMapping = Document.SelectNodes("/edmx:Edmx/edmx:Runtime/edmx:Mappings/cs:Mapping", nsmgr); 
      XmlNode EntityContainerMapping_Node = EntityContainerMapping[0]; 
      XmlElement EntityContainerMappingNode_XmlElement = EntityContainerMapping_Node as XmlElement; 

      // update name attribute of all EntitySetMapping nodes 

      //get all EntitySetMapping nodes 
      XmlNodeList EntitySetMappinglist = EntityContainerMappingNode_XmlElement.GetElementsByTagName("EntitySetMapping"); 

      //get all EntityTypeMapping nodes 
      XmlNodeList EntityTypeMappinglist = EntityContainerMappingNode_XmlElement.GetElementsByTagName("EntityTypeMapping"); 

      //get all ScalarProperty nodes 
      XmlNodeList ScalarPropertyist = EntityContainerMappingNode_XmlElement.GetElementsByTagName("ScalarProperty"); 

      foreach (XmlNode ScalarPropertyNode in ScalarPropertyist) 
      { 
       XmlAttribute nameAttribute = ScalarPropertyNode.Attributes["Name"]; 
       nameAttribute.Value = UppercaseFirst(nameAttribute.Value); 
      } 

      Console.WriteLine("MappingSection updated.."); 
     } 

     /// <summary> 
     /// Uppercases the first. 
     /// </summary> 
     /// <param name="name">The name.</param> 
     /// <returns></returns> 
     private static string UppercaseFirst(string name) 
     { 

      return char.ToUpper(name[0]) + name.Substring(1); 

     } 
    } 
} 

Uso:

  RenameManager.FilePath = @"C:\Users\therath\testApp\Model1.edmx"; 
      // Path of edmx file in the your solution 
      RenameManager.Document.Load(@RenameManager.FilePath); 
      RenameManager.nsmgr = new XmlNamespaceManager(RenameManager.Document.NameTable); 
      RenameManager.nsmgr.AddNamespace("edmx", "http://schemas.microsoft.com/ado/2008/10/edmx"); 
      RenameManager.nsmgr.AddNamespace("edm", "http://schemas.microsoft.com/ado/2008/09/edm"); 
      //nsmgr.AddNamespace("ssdl", "http://schemas.microsoft.com/ado/2009/02/edm/ssdl"); 
      RenameManager.nsmgr.AddNamespace("cs", "http://schemas.microsoft.com/ado/2008/09/mapping/cs"); 

      try 
      { 
       RenameManager.UpdateConceptualModelsSection(); 
       RenameManager.UpdateMappingsSection(); 
       RenameManager.Document.Save(@RenameManager.FilePath); 
      } 

      catch (Exception ex) 
      { 
       MessageBox.Show(ex.Message.ToString()); 
      } 

Si genera el nuevo edmx puede que tenga que ejecutar esta herramienta de nuevo.

1

hay maneras de hacer eso, algunos de los que ya se ha comentado en otras ..

encontré una clase que hace que ...

namespace System.Data.Entity.ModelConfiguration.Conventions 
{ 
    /// <summary> 
/// Convention to convert any data types that were explicitly specified, via data  annotations or <see cref="T:System.Data.Entity.DbModelBuilder"/> API, 
///     to be lower case. The default SqlClient provider is case sensitive and requires data types to be lower case. This convention 
///     allows the <see cref="T:System.ComponentModel.DataAnnotations.ColumnAttrbiute"/> and <see cref="T:System.Data.Entity.DbModelBuilder"/> API to be case insensitive. 
/// 
/// </summary> 
public sealed class ColumnTypeCasingConvention : IDbConvention<DbTableColumnMetadata>, IConvention 
{ 
    internal ColumnTypeCasingConvention() 
{ 
} 

[SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase")] 
void IDbConvention<DbTableColumnMetadata>.Apply(DbTableColumnMetadata tableColumn, DbDatabaseMetadata database) 
{ 
    if (string.IsNullOrWhiteSpace(tableColumn.TypeName)) 
    return; 
    tableColumn.TypeName = tableColumn.TypeName.ToLowerInvariant(); 
} 

}}

explícita implementación de idbconvertion hace eso que usted puede implementar

otra es

vaya a la Solución => y busca la carpeta obj/debug/edmxresourcestoembed

hay tres archivos db.csdl, db.msl, db.ssdl editar el archivo MSL => verá mapeo para cada mesa como como debajo.

<EntitySetMapping Name="Address"> 
    <EntityTypeMapping TypeName="IsTypeOf(AdventureWorksLTModel.Address)"> 
    <MappingFragment StoreEntitySet="Address"> 
     <ScalarProperty Name="AddressID" ColumnName="AddressID" /> 
     <ScalarProperty Name="AddressLine1" ColumnName="AddressLine1" /> 
     <ScalarProperty Name="AddressLine2" ColumnName="AddressLine2" /> 
     <ScalarProperty Name="City" ColumnName="City" /> 
     <ScalarProperty Name="StateProvince" ColumnName="StateProvince" /> 
     <ScalarProperty Name="CountryRegion" ColumnName="CountryRegion" /> 
     <ScalarProperty Name="PostalCode" ColumnName="PostalCode" /> 
     <ScalarProperty Name="rowguid" ColumnName="rowguid" /> 
     <ScalarProperty Name="ModifiedDate" ColumnName="ModifiedDate" /> 
    </MappingFragment> 
    </EntityTypeMapping> 
</EntitySetMapping> 
0

bien que se puede editar los nombres de la edmx en realidad, pero cada vez que actualice la base de datos es hora de volver a hacerlo de nuevo.

El único enfoque viable al usar tipos de datos de tipo edmx es tener los nombres correctos (con letras mayúsculas) en las tablas de la base de datos o será tedioso.

En su lugar, puede causar el uso del enlace a sql, en cuyo caso usted define sus clases de datos y solo proporciona una propiedad de nombre. Pero se advirtió que este enfoque es mucho más manual y está siendo cancelado en la mayoría de los lugares porque requiere mucho más pensamiento para configurar esa autogeneración de edmx, que es un clic, un clic, el próximo enfoque.

Así que sí, puede editar los nombres en el edmx, pero considere abandonar su camelCasing para tablas, en homenaje a edmx que le ahorra mucho trabajo, o sus clases de proxy generadas .net se verán extrañas, como sabes.

12

Sí, sí. Aquí se puede ver el ejemplo completo:

using System; 
using System.Data.Entity; 

namespace ConsoleApplication1 
{ 
    class MyDbContext : DbContext 
    { 
     protected override void OnModelCreating(DbModelBuilder modelBuilder) 
     { 
      base.OnModelCreating(modelBuilder); 
      modelBuilder.Properties().Configure(c => 
      { 
       var name = c.ClrPropertyInfo.Name; 
       var newName = char.ToLower(name[0]) + name.Substring(1); 
       c.HasColumnName(newName); 
      }); 
     } 

     public MyDbCondenxt(string cs) : base(cs) 
     { 

     } 

     public DbSet<MyModel> MyModels { get; set; } 

    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var context = new MyDbContext ("DefaultConnection"); 
      context.MyModels.Add(new MyModel{SomeText = "hello"}); 
      context.SaveChanges(); 

      Console.ReadLine(); 
     } 
    } 

    class MyModel 
    { 
     public int Id { get; set; } 
     public string SomeText { get; set; } 
    } 


} 

El nombre de la propiedad es "SomeText" y el nombre de la columna es "someText".

+0

Estoy usando EF Core 2.0.0 y parece que 'modelBuilder.Properties()' no existe. ¿Hay otras soluciones para EF Core? – Poulad

+0

Encontré mi respuesta aquí: https://github.com/aspnet/EntityFrameworkCore/issues/5159#issuecomment-256300665 – Poulad

Cuestiones relacionadas