2010-04-10 24 views
19

Un esquema de base de datos existente tiene claves únicas, no primarias, y algunas claves externas que dependen de ellas.Claves únicas en Entity Framework 4

¿Es posible definir claves únicas, que no son claves principales, en Entity Framework v4? ¿Cómo?

Respuesta

8

He intentado definir las siguientes tablas:

  • órdenes [Id (primaria, la identidad), ClientName, FriendlyOrderNum (única)]
  • de pedido [Id (primaria, la identidad), FriendlyOrderNum (único), NombreDeElemento]

Y un mapeo clave externa de OrderItems.FriendlyOrderNum (Mant) a Orders.FriendlyOrderNum (uno).

Si las claves no primarias únicas son posibles los siguientes SSDL debería funcionar:

<Schema Namespace="EfUkFk_DbModel.Store" Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2008" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2009/02/edm/ssdl"> 
    <EntityContainer Name="EfUkFk_DbModelStoreContainer"> 
     <EntitySet Name="OrderItems" EntityType="EfUkFk_DbModel.Store.OrderItems" store:Type="Tables" Schema="dbo" /> 
     <EntitySet Name="Orders" EntityType="EfUkFk_DbModel.Store.Orders" store:Type="Tables" Schema="dbo" /> 
    </EntityContainer> 
    <EntityType Name="OrderItems"> 
     <Key> 
     <PropertyRef Name="RowId" /> 
     </Key> 
     <Property Name="RowId" Type="bigint" Nullable="false" StoreGeneratedPattern="Identity" /> 
     <Property Name="OrderNum" Type="char" Nullable="false" MaxLength="5" /> 
     <Property Name="ItemName" Type="varchar" MaxLength="100" /> 
    </EntityType> 
    <!--Errors Found During Generation: 
    warning 6035: The relationship 'FK_OrderItems_Orders' has columns that are not part of the key of the table on the primary side of the relationship. The relationship was excluded. 
    --> 
    <EntityType Name="Orders"> 
     <Key> 
     <PropertyRef Name="RowId" /> 
     </Key> 
     <Property Name="RowId" Type="bigint" Nullable="false" StoreGeneratedPattern="Identity" /> 
     <Property Name="ClientName" Type="varchar" MaxLength="100" /> 
     <Property Name="OrderNum" Type="char" Nullable="false" MaxLength="5" /> 
    </EntityType> 

    <!-- AsafR --> 
    <Association Name="FK_OrderItems_Orders"> 
     <End Role="Orders" Type="EfUkFk_DbModel.Store.Orders" Multiplicity="1"> 
     </End> 
     <End Role="OrderItems" Type="EfUkFk_DbModel.Store.OrderItems" Multiplicity="*" /> 
     <ReferentialConstraint> 
     <Principal Role="Orders"> 
      <PropertyRef Name="OrderNum" /> 
     </Principal> 
     <Dependent Role="OrderItems"> 
      <PropertyRef Name="OrderNum" /> 
     </Dependent> 
     </ReferentialConstraint> 
    </Association> 
    </Schema></edmx:StorageModels> 

No lo hace. Tampoco hay posibilidad de agregar más < elementos clave > en <EntityType>.

Mi conclusión es que las claves únicas no primarios no se apoyan en EF 4.

3

Puede usar la validación de DataAnnotations también.

que he creado this (UniqueAttribute) clase, que hereda ValidationAttribute, y cuando se aplica a una propiedad, se recuperarán los valores de esa columna y validado en contra, durante la validación.

Puede tomar el código sin procesar desde here.

+1

¿Funciona este atributo para la combinación de columnas? –

+0

Incluso no en EF6 :( – eka

10

Me encontré con el mismo problema no hace mucho tiempo.

Me dieron una base de datos con algunas tablas (ver a continuación).

public class ClinicDbContext : DbContext 
{ 
    public DbSet<User> Users { get; set; } 
    public DbSet<Doctor> Doctors { get; set; } 
    public DbSet<Patient> Patients { get; set; } 
    public DbSet<Secretary> Secretarys { get; set; } 
    public DbSet<Disease> Diseases { get; set; } 
    public DbSet<Consultation> Consultations { get; set; } 
    public DbSet<Administrator> Administrators { get; set; } 
} 

la tabla de usuarios se describe así:

public class User 
{ 
    [Key] 
    public Guid UserId { get; set; } 

    public string UserName { get; set; } 

    public string Password { get; set; } 

    public string Name { get; set; } 
    public string Surname { get; set; } 
    public string IdentityCardNumber { get; set; } 
    public string PersonalNumericalCode { get; set; } 
    public DateTime DateOfBirth { get; set; } 
    public string Address { get; set; } 
} 

A continuación, se me pidió que asegurarse de que todos los 'Nombre de usuario' atributos sería único. Dado que no hay anotaciones para eso, tuve que resolver un problema. Y aquí está:

En primer lugar, he cambiado de clase de contexto de base de datos para tener este aspecto:

public class ClinicDbContext : DbContext 
{ 
    public DbSet<User> Users { get; set; } 
    public DbSet<Doctor> Doctors { get; set; } 
    public DbSet<Patient> Patients { get; set; } 
    public DbSet<Secretary> Secretarys { get; set; } 
    public DbSet<Disease> Diseases { get; set; } 
    public DbSet<Consultation> Consultations { get; set; } 
    public DbSet<Administrator> Administrators { get; set; } 

    public class Initializer : IDatabaseInitializer<ClinicDbContext> 
    { 
     public void InitializeDatabase(ClinicDbContext context) 
     { 
      if (!context.Database.Exists() || !context.Database.CompatibleWithModel(false)) 
      { 
       if (context.Database.Exists()) 
       { 
        context.Database.Delete(); 
       } 
       context.Database.Create(); 

       context.Database.ExecuteSqlCommand("CREATE INDEX IX_Users_UserName ON dbo.Users (UserName)"); 
      } 
     } 
    } 
} 

La parte importante de lo anterior es el comando sql que altera la mesa mediante la aplicación de un único índice en nuestra columna deseada -> Nombre de usuario en nuestro caso.

Este método puede ser llamado desde la clase principal, por ejemplo:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Database.SetInitializer<ClinicDbContext>(new ClinicDbContext.Initializer()); 

     using (var ctx = new ClinicDbContext()) 
     { 
      Console.WriteLine("{0} products exist in the database.", ctx.Users.Count()); 
     } 

     Console.WriteLine("Press any key to exit."); 
     Console.ReadKey(); 
    } 
} 

La última cuestión, que se produjo al intentar ejecutar el Programa clase fue el siguiente: columna de la tabla es de un tipo que no es válido para usar como columna clave en un índice

Para resolver este problema, acabo de agregar un [MaxLength (250)] anotación para el atributo UserName.

Aquí es cómo la clase usuario ve en el final:

public class User 
{ 
    [Key] 
    public Guid UserId { get; set; } 

    [MaxLength(250)] 
    public string UserName { get; set; } 

    public string Password { get; set; } 

    public string Name { get; set; } 
    public string Surname { get; set; } 
    public string IdentityCardNumber { get; set; } 
    public string PersonalNumericalCode { get; set; } 
    public DateTime DateOfBirth { get; set; } 
    public string Address { get; set; } 
} 

espero que va a resolver su problema también!

16

Entity Framework 6.1 ahora admite funciones únicas con anotaciones de datos y API fluida.

datos de anotaciones (Reference)

public class MyEntityClass 
{ 
    [Index(IsUnique = true)] 
    [MaxLength(255)] // for code-first implementations 
    public string MyUniqueProperty{ get; set; } 
} 

API Fluido (Reference)

public class MyContext : DbContext 
    { 
     protected override void OnModelCreating(DbModelBuilder modelBuilder) 
     { 
      modelBuilder 
       .Entity<MyEntityClass>() 
       .Property(t => t.MyUniqueProperty) 
       .HasMaxLength(255) // for code-first implementations 
       .HasColumnAnnotation( 
        "Index", 
        new IndexAnnotation(new[] 
         { 
          new IndexAttribute("Index") { IsUnique = true } 
         }))); 
     } 
    } 
} 

usted tiene que aplicar un índice y establecer la propiedad única de verdad. Por defecto, los índices no son únicos según la documentación.

Y también debe instalar el paquete NuGet de Entity Framework 6.1 en su proyecto para utilizar la nueva API para los índices.

Nota sobre las implementaciones de primer código: A VARCHAR(MAX) no puede formar parte de una restricción única. Debe especificar la longitud máxima como anotación de datos o en la API Fluent.

+0

Esto compila para mí, pero obtengo un error de tiempo de ejecución que 'Column 'Email' en la tabla 'dbo.Users' es de un tipo que no es válido para usar como columna clave en un índice. 'Email' es una cadena pública, al igual que' MyUniqueProperty'. – djs

+0

Está funcionando bien aquí, e hice muchos intentos para reproducir su error, pero no pude. ¿Abriría una nueva pregunta con todos los detalles, incluyendo ¿La versión de EF y el seguimiento de la pila completa y su clase? Por favor, agregue un comentario aquí con el enlace para que pueda investigar. Tx! – BonanzaOne

+1

Mi problema es porque estoy usando una implementación de código primero, que crea la columna 'Correo electrónico' como' NVARCHAR (MAX) 'de forma predeterminada. Hice una edición para abordar este caso. Su solución funciona bien para mí ahora! – djs

Cuestiones relacionadas