I try to implement Entity Framework Code First method. I have two class which are Student and Standard(Grades). This is my Standard model:
class Standard
{
public Standard()
{
}
public int StandardId { get; set; }
public string StandardName { get; set; }
public ICollection<Student> Students { get; set; }
}
and Student model:
class Student
{
public Student()
{
}
public int StudentID { get; set; }
public string StudentName { get; set; }
public DateTime? DateOfBirth { get; set; }
public byte[] Photo { get; set; }
public decimal Height { get; set; }
public float Weight { get; set; }
public Standard Standard { get; set; }
}
Context:
class SchoolContext : DbContext
{
public SchoolContext() : base()
{
}
public DbSet<Student> Students { get; set; }
public DbSet<Standard> Standards { 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=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="(LocalDb)\MSSQLLocalDB" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>
and main method:
class Program
{
static void Main(string[] args)
{
using (var ctx = new SchoolContext())
{
ctx.Database.Initialize(force:true);
Student stud = new Student() { StudentName = "New Student" };
ctx.Students.Add(stud);
ctx.SaveChanges();
}
}
}
It compiles and runs but the database does not exist. Where do I make wrong ?
Related
How to resolve my "HelloEFCore" .NET Core console app exception? I use Npgsql Entity Framework Core Provider (https://www.npgsql.org/efcore/)
Unable to create an object of type 'AppContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
It occurs when I try to do initial migration
dotnet ef migrations add CreateDatabase
Code that I'm working with:
Program.cs
class Program
{
static void Main(string[] args)
{
AppContext a = new AppContext("Server=127.0.0.1; port=5432; user_id=postgres; password=root; database=db; pooling=true");
}
}
Product.cs
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Description { get; set; }
public int Quantity { get; set; }
public int BrandId { get; set; }
public Brand Brand { get; set; }
}
Brand.cs
public class Brand
{
public int BrandId { get; set; }
public string Name { get; set; }
public List<Product> Products { get; set; } = new List<Product>();
}
AppContext.cs
public class AppContext : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<Brand> Brands { get; set; }
private readonly string _connectionString;
public AppContext(string connectionString)
{
_connectionString = connectionString ??
throw new ArgumentException("connectionString is empty.");
}
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
builder.UseNpgsql(_connectionString);
}
}
efstart.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.8" />
<PackageReference Include="Npgsql" Version="4.1.3"/>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.3"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.4"/>
</ItemGroup>
</Project>
Application compiles well. I use pgAdmin on Ubuntu 20.04.
You need to implement IDesignTimeDbContextFactory interface to make your solution work without any problems.
public class AppContext Factory : IDesignTimeDbContextFactory< AppContext>
{
public AppContext CreateDbContext(string[] args)
{
var builder = new DbContextOptionsBuilder<AppContext>();
builder.UseNpgsql(connectionString);
return new DataContext(builder.Options);
}
}
I am trying to create a code first database creation. I have 2 connection strings:
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=DESKTOP-1111\SERVER_2014; database=the_userdb;user=sa; password=myPassword" providerName="System.Data.SqlClient" />
<add name="PmisDatabaseContext" connectionString="Data Source=DESKTOP-1111\SERVER_2014; database=the_database;user=sa; password=myPassword" providerName="System.Data.SqlClient" />
</connectionStrings>
At first, I was able to add a migration using this:
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public bool IsActivated { get; set; }
public DateTime EnrollDate { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{ }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//AspNetUsers -> User
modelBuilder.Entity<ApplicationUser>()
.ToTable("User");
//AspNetRoles -> Role
modelBuilder.Entity<IdentityRole>()
.ToTable("Role");
//AspNetUserRoles -> UserRole
modelBuilder.Entity<IdentityUserRole>()
.ToTable("UserRole");
//AspNetUserClaims -> UserClaim
modelBuilder.Entity<IdentityUserClaim>()
.ToTable("UserClaim");
//AspNetUserLogins -> UserLogin
modelBuilder.Entity<IdentityUserLogin>()
.ToTable("UserLogin");
}
}
then I 'enabled migrations' then 'add-migration InitialDatabase' then 'update-database' and was able to successfully created a new database with the tables for logging in.
Now I want to create a new database with a table named ImageLibraries so I did this in my model:
[Table("ImageLibrary")]
public class ImageLibrary
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
[Required]
public string UserId { get; set; }
}
then added:
public class PmisDatabaseContext : DbContext
{
public PmisDatabaseContext()
: base("name=PmisDatabaseContext")
{
Database.SetInitializer<PmisDatabaseContext>(new CreateDatabaseIfNotExists<PmisDatabaseContext>());
}
public virtual DbSet<ImageLibrary> ImageLibraries { get; set; }
}
When I try to 'add-migration AddedImageLibrary', in my migrations folder, I get the 'up()' and 'down()' without anything in it. It's not creating the new database and table. Can you please show me how to do this right. Thank you.
Why am I receiving errors when using views and controllers created via scaffolding with MVC 5 / EF 6 (inheritance) derived classes?
My background: I am a previous Powerbuilder (client/server programmer) that is endeavoring to learn web-based programming.
I chose ASP.NET and purchased an MSDN license to use Visual Studio 2013 and have been learning by books, online training and plain old hacking on the computer.
The best test is to create some sample application and so here I am. I am learning the MVC and Code First EF because there is so much good info and samples to be had.
However, I am stuck on my inheritance example.
I have 3 classes: AircrewMember derived from Airman derived from Person. They compile without error.
I have a class DbInitializer so "Code First" will create the database. I actually use SQL scripts to load my test data.
I have a class StanEvalDb for the database context info.
I have included pertinent information from web.config.
The problem:
When I use scaffolding to create a controller and views based off of the Airman class (derived from Person), the result returns with errors.
Airman airman = db.People.Find(id);
Error 1
Cannot implicitly convert type 'SEMX1.Entities.Person' to 'SEMX1.Entities.Airman'. An explicit conversion exists (are you missing a cast?)
D:\Projects\VC2013\2015\06-Jun\SEMX1\SEMX1.Web\Controllers\AirmenController.cs 31 29 SEMX1.Web
I think I understand the Table per Hierarchy (TPH) and that physically only one table (People) is created to house all "3" tables.
I am at a loss... I have googled and read many articles but I have no idea how to proceed. Has anyone seen this or tried this?
I assume I am overlooking something simple but I am out of ideas. Any help would be appreciated!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SEMX1.Entities
{
public class Person
{
public virtual int PersonId { get; set; }
[DisplayName("First Name* ")]
[StringLength(40)]
[Required(ErrorMessage = "The First Name field is required.")]
public virtual string PersonFirstName { get; set; }
[DisplayName("Middle Initial ")]
[StringLength(2)]
public virtual string PersonMidInit { get; set; }
[DisplayName("Last Name* ")]
[StringLength(50)]
[Required(ErrorMessage = "The Last Name field is required.")]
public virtual string PersonLastName { get; set; }
[DisplayName("SSN* ")]
[StringLength(11)]
[Required(ErrorMessage = "The SSN field is required.")]
public virtual string PersonSSN { get; set; }
[DisplayName("DOB* ")]
[Required(ErrorMessage = "The DOB field is required.")]
public virtual DateTime? PersonDOB { get; set; }
public virtual int CivilRankId { get; set; }
//public virtual int LifeEventId { get; set; }
public virtual ICollection<LifeEvent> LifeEvents { get; set; }
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SEMX1.Entities
{
public class Airman : Person
{
public virtual int MilitaryRankId { get; set; }
public virtual int MilitaryUnitId { get; set; }
public virtual int AfscId { get; set; }
public virtual ICollection<CareerEvent> CareerEvents { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SEMX1.Entities
{
public class AircrewMember : Airman
{
public virtual int AviationTypeId { get; set; }
public virtual int AirMissionId { get; set; }
public virtual int AircraftId { get; set; }
public virtual int CrewPositionId { get; set; }
public virtual int ExperienceRatingId { get; set; }
public virtual int AirmanshipId { get; set; }
public virtual int TacticalDayRatingId { get; set; }
public virtual int TacticalNightRatingId { get; set; }
public virtual ICollection<AircrewEvent> AircrewEvents { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using SEMX1.Entities;
using System.IO;
namespace SEMX1.Web.DataContexts
{
public class DbInitializer : System.Data.Entity.DropCreateDatabaseIfModelChanges<StanEvalDb>
{
protected override void Seed(StanEvalDb context)
{
base.Seed(context);
// using SQL scripts to load database with test data
// easier way to get around identity key field problems
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using SEMX1.Entities;
using System.Data.Entity.ModelConfiguration.Conventions;
namespace SEMX1.Web.DataContexts
{
public class StanEvalDb : DbContext
{
public StanEvalDb() : base("StanEvalContext")
{
Database.SetInitializer<StanEvalDb>(new DbInitializer());
}
public DbSet<Person> People { get; set; }
public DbSet<LifeEvent> LifeEvents { get; set; }
public DbSet<CivilRank> CivilRanks { get; set; }
public DbSet<MilitaryRank> MilitaryRanks { get; set; }
public DbSet<MilitaryUnit> MilitaryUnits { get; set; }
public DbSet<MilUnitType> MilUnitTypes { get; set; }
public DbSet<AFSC> AFSCList { get; set; }
public DbSet<CareerEvent> CareerEvents { get; set; }
public DbSet<Airman> Airmen { get; set; }
public DbSet<AviationType> AviationTypes { get; set; }
public DbSet<AirMission> AirMissions { get; set; }
public DbSet<Aircraft> AircraftList { get; set; }
public DbSet<CrewPosition> CrewPositions { get; set; }
public DbSet<ExperienceRating> ExperienceRatings { get; set; }
public DbSet<Airmanship> AirmanshipList { get; set; }
public DbSet<TacticalDayRating> TacticalDayRatings { get; set; }
public DbSet<TacticalNightRating> TacticalNightRatings { get; set; }
public DbSet<AircrewEvent> AircrewEvents { get; set; }
public DbSet<AircrewMember> Aircrew { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
//modelBuilder.Entity<Person>()
// .HasMany(p => p.LifeEvents).WithMany(l => l.People)
// .Map(t => t.MapLeftKey("PersonID")
// .MapRightKey("LifeEventID")
// .ToTable("LifeEventPersons"));
//modelBuilder.Entity<Airman>()
// .HasMany(a => a.CareerEvents).WithMany(c => c.Airmen)
// .Map(t => t.MapLeftKey("PersonID")
// .MapRightKey("CareerEventID")
// .ToTable("CareerEventAirmen"));
//modelBuilder.Entity<AircrewMember>()
// .HasMany(a => a.AircrewEvents).WithMany(c => c.Aircrew)
// .Map(t => t.MapLeftKey("PersonID")
// .MapRightKey("AircrewEventID")
// .ToTable("AircrewEventAircrew"));
}
}
}
Web.config (Pertinent Information)
<configuration>
<configSections>
<section name="entityFramework"
type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
requirePermission="false" />
</configSections>
<connectionStrings>
<add name="StanEvalContext"
connectionString="Data Source=REDCARBOSS2-LAP\RCB2SRV2012;Initial Catalog=DB_25213_SEMX1;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False"
providerName="System.Data.SqlClient" />
</connectionStrings>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient"
type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using SEMX1.Entities;
using SEMX1.Web.DataContexts;
namespace SEMX1.Web.Controllers
{
public class AirmenController : Controller
{
private StanEvalDb db = new StanEvalDb();
// GET: Airmen
public ActionResult Index()
{
return View(db.People.ToList());
}
// GET: Airmen/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Airman airman = db.People.Find(id);
if (airman == null)
{
return HttpNotFound();
}
return View(airman);
}
// GET: Airmen/Create
public ActionResult Create()
{
return View();
}
// POST: Airmen/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "PersonId,PersonFirstName,PersonMidInit,PersonLastName,PersonSSN,PersonDOB,CivilRankId,MilitaryRankId,MilitaryUnitId,AfscId")] Airman airman)
{
if (ModelState.IsValid)
{
db.People.Add(airman);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(airman);
}
// GET: Airmen/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Airman airman = db.People.Find(id);
if (airman == null)
{
return HttpNotFound();
}
return View(airman);
}
// POST: Airmen/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "PersonId,PersonFirstName,PersonMidInit,PersonLastName,PersonSSN,PersonDOB,CivilRankId,MilitaryRankId,MilitaryUnitId,AfscId")] Airman airman)
{
if (ModelState.IsValid)
{
db.Entry(airman).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(airman);
}
// GET: Airmen/Delete/5
public ActionResult Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Airman airman = db.People.Find(id);
if (airman == null)
{
return HttpNotFound();
}
return View(airman);
}
// POST: Airmen/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Airman airman = db.People.Find(id);
db.People.Remove(airman);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
The error says that it cannot implicitly cast and is asking you to explicitly cast. Try replacing this:
Airman airman = db.People.Find(id);
With:
Airman airman = (Airman)db.People.Find(id);
This is my context class
public class HospitalContext : DbContext
{
public DbSet<Patient> Patients { get; set; }
public DbSet<Doctor> Doctors { get; set; }
public DbSet<Appointment> Appointments { get; set; }
public DbSet<Schedule> Schedule { get; set; }
}
And my connection string
<add name="DbContext"
providerName="System.Data.SqlClient"
connectionString="Data Source=(LocalDb)\v11.0;
Initial Catalog=HospitalProject;
Integrated Security=True;" />
I'd like to know why when I run the application, the database name is
HospitalProject.Models.HospitalContext
instead of HospitalProject.
Thanks for helping
Try renaming connection string to HospitalContext instead of DbContext
An existing DB schema has unique, non-primary, keys, and some foreign keys that rely on them.
Is it possible to define unique keys, which are not primary keys, in Entity Framework v4? How?
The Entity Framework 6.1 now supports uniques with both Data Annotations and Fluent API.
Data Annotations (Reference)
public class MyEntityClass
{
[Index(IsUnique = true)]
[MaxLength(255)] // for code-first implementations
public string MyUniqueProperty{ get; set; }
}
Fluent API (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 }
})));
}
}
}
You have to apply an index and set the unique property to true. By default, indexes are non-unique according to documentation.
And also you have to install the Entity Framework 6.1 NuGet package in your project in order to use the new API for indexes.
Note about code-first implementations: A VARCHAR(MAX) cannot be part of a unique constraint. You must specify the maximum length either as a Data Annotation or in the Fluent API.
See also this MSDN blog post: http://blogs.msdn.com/b/efdesign/archive/2011/03/09/unique-constraints-in-the-entity-framework.aspx. In brief, this isn't supported in V4, though the EF team seems to have plans to support it in future releases.
I came across the same problem not long ago.
I was given a database with a few tables (see below).
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; }
}
The Users table was described like this:
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; }
}
Next, I was asked to make sure that all the 'UserName' attributes would be unique. Since there is no annotation for that, I had to figure out a work-around. And here it is:
First, I changed my database context class to look like this:
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 )");
}
}
}
}
The important part from above is the sql command which alters the table by enforcing a unique index on our desired column -> UserName in our case.
This method can be called from the main class for example:
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();
}
}
The final issue, which occurred when trying to run the the Program class was the following: column in table is of a type that is invalid for use as a key column in an index
To solve this issue, I just added a [MaxLength(250)] annotation for the UserName attribute.
Here is how the User class looks in the end:
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; }
}
Hope it will solve your problem too!
I've tried defining the following tables:
Orders [Id (primary, identity), ClientName, FriendlyOrderNum (unique)]
OrderItems [Id (primary, identity), FriendlyOrderNum (unique), ItemName]
And a foreign key mapping from OrderItems.FriendlyOrderNum (Mant) to Orders.FriendlyOrderNum (one).
If unique non-primary keys are possible the following SSDL should work:
<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>
It doesn't. There's also no possibility for adding more <key> elements in an <EntityType>.
My conclusion is that non-primary unique keys are not support in EF 4.
You can use DataAnnotations validation as well.
I've created this (UniqueAttribute) class, that inherits ValidationAttribute, and when applied to a property, the values of that column will be retrieved and validated against, during validation.
You can grab the raw code from here.