一个已存在的数据库架构具有独特的非主键和一些依赖它们的外键。
在实体框架 v4 中,是否可以定义不是主键的唯一键?如果可以,如何实现?
一个已存在的数据库架构具有独特的非主键和一些依赖它们的外键。
在实体框架 v4 中,是否可以定义不是主键的唯一键?如果可以,如何实现?
实体框架6.1现在支持使用数据注释和流畅的API来定义唯一性。
数据注释 (参考文献)
public class MyEntityClass
{
[Index(IsUnique = true)]
[MaxLength(255)] // for code-first implementations
public string MyUniqueProperty{ get; set; }
}
流畅API (参考文献)
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 }
})));
}
}
}
你需要应用索引并将 unique 属性设置为 true。根据文档,默认情况下,索引是非唯一的。
同时,你还需要在项目中安装 Entity Framework 6.1 NuGet 包,以便使用索引的新 API。
关于代码优先实现的注意事项: VARCHAR(MAX)
不能成为唯一约束的一部分。你必须在 Data Annotation 或 Fluent API 中指定最大长度。
此外,还要参考这篇MSDN博客文章:http://blogs.msdn.com/b/efdesign/archive/2011/03/09/unique-constraints-in-the-entity-framework.aspx。 简而言之,这在V4中不受支持,尽管EF团队似乎计划在未来的发布版本中提供支持。
我不久前遇到了同样的问题。
我得到了一个带有几个表的数据库(见下文)。
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 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; }
}
接下来,我被要求确保所有'UserName'属性都是唯一的。由于没有对此进行注释,我不得不想出一个解决方法。以下是我的解决方案:
首先,我将我的数据库上下文类更改为以下内容:
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 )");
}
}
}
}
以上中重要的部分是SQL命令,它通过在所需的列(在我们的案例中为UserName)上强制实施唯一索引来更改表格。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();
}
}
尝试运行程序类时发生的最后一个问题是: 表中的列是无效类型,不适用于索引的键列
为了解决这个问题,我只需在UserName属性上添加[MaxLength(250)] 注释。
以下是最终的User类:
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; }
}
希望这也能解决你的问题!
我尝试定义以下表格:
并从OrderItems.FriendlyOrderNum(Mant)到Orders.FriendlyOrderNum(one)建立了一个外键映射。
如果可能使用唯一的非主键,则以下SSDL应该可以工作:
<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>
不行。在<EntityType>中也无法添加更多的<key>元素。
我的结论是EF 4不支持非主要唯一键。
表'dbo.Users'中的列'Email'的类型无效,不能用作索引的键列。
Email
是一个公共字符串,就像MyUniqueProperty
一样。 - djs