name - Claves únicas en Entity Framework 4
modelbuilder entity framework (5)
Consulte también esta publicación del blog de MSDN: http://blogs.msdn.com/b/efdesign/archive/2011/03/09/unique-constraints-in-the-entity-framework.aspx . En resumen, esto no se admite en V4, aunque el equipo de EF parece que tiene planes de admitirlo en futuras versiones.
Un esquema de base de datos existente tiene claves únicas, no primarias y algunas claves externas que dependen de ellas.
¿Es posible definir claves únicas, que no son claves principales, en Entity Framework v4? ¿Cómo?
Entity Framework 6.1 ahora es compatible con Uniques con Anotaciones de datos y API Fluent.
Anotaciones de datos ( Reference )
public class MyEntityClass
{
[Index(IsUnique = true)]
[MaxLength(255)] // for code-first implementations
public string MyUniqueProperty{ get; set; }
}
API fluida ( 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 }
})));
}
}
}
Debe aplicar un índice y establecer la propiedad única en verdadero. De forma predeterminada, los índices no son únicos según la documentación.
Y también tiene que instalar el paquete Entity Framework 6.1 NuGet en su proyecto para poder utilizar la nueva API para los índices.
Nota sobre implementaciones de código primero: Un VARCHAR(MAX)
no puede ser parte de una restricción única. Debe especificar la longitud máxima como Anotación de datos o en la API Fluent.
He intentado definir las siguientes tablas:
- Pedidos [Id (primario, identidad), ClientName, FriendlyOrderNum (único)]
- Artículos de pedido [Id (primario, identidad), FriendlyOrderNum (único), ItemName]
Y una asignación de clave externa de OrderItems.FriendlyOrderNum (Mant) a Orders.FriendlyOrderNum (uno).
Si son posibles claves no primarias únicas, el siguiente 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 <key> en un <EntityType>.
Mi conclusión es que las claves únicas no primarias no son compatibles con EF 4.
Me encontré con el mismo problema no hace mucho tiempo.
Me dieron una base de datos con algunas tablas (ver más abajo).
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 fue descrita 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, me pidieron que me asegurara de que todos los atributos de '' Nombre de usuario '' fueran únicos. Como no hay ninguna anotación para eso, tuve que encontrar una solución alternativa. Y aquí está:
Primero, cambié mi 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 arriba es el comando sql que altera la tabla al imponer un índice único en nuestra columna deseada -> Nombre de usuario en nuestro caso.
Este método se puede llamar 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();
}
}
El último problema, que se produjo al intentar ejecutar la clase del programa , fue el siguiente: la columna en la tabla es de un tipo que no es válido para su uso como una columna clave en un índice
Para resolver este problema, acabo de agregar una anotación de [MaxLength (250)] para el atributo UserName.
Aquí es cómo se ve la clase de usuario al 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 resuelva tu problema también!