Unique keys in Entity Framework 4 - entity-framework

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.

Related

Xamarin Forms CarouselView does not show images

I have two Models and a ViewModels for articles and posts from DB . One of them like this :
public class ArticleData
{
public string Id { get; set; }
public string Title { get; set; }
public string Subtitle { get; set; }
public string Body { get; set; }
public string Section { get; set; }
public string Author { get; set; }
public string Avatar { get; set; }
public string BackgroundImage { get; set; }
public string Quote { get; set; }
public string QuoteAuthor { get; set; }
public string When { get; set; }
public string Followers { get; set; }
public string Likes { get; set; }
}
and i use BackgroundImage in CarouselView like this :
<CarouselView
HeightRequest="300"
Margin="0"
VerticalOptions="Center"
ItemsSource="{ Binding Images.Articles }">
<CarouselView.ItemTemplate>
<DataTemplate>
<Grid>
<ffimageloading:CachedImage
Source="{ Binding BackgroundImage }"
VerticalOptions="Fill"
Aspect="AspectFill" />
</Grid>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
And there is no problem with CarouselView and it shows images . But with another Model that likes this
public class FollowingsPostResponse
{
public List<FPostModel> data { get; set; }
public bool isSuccess { get; set; }
public int statusCode { get; set; }
public string message { get; set; }
}
public class FPostModel
{
public int id { get; set; }
public List<string> images { get; set; }
public string userName { get; set; }
public string userProfileImage { get; set; }
public string cityName { get; set; }
public int likesCounts { get; set; }
public string postCaption { get; set; }
}
and use like this
<CarouselView
HeightRequest="300"
Margin="0"
VerticalOptions="Center"
ItemsSource="{ Binding Home.Post }">
<CarouselView.ItemTemplate>
<DataTemplate>
<Grid>
<ffimageloading:CachedImage
Source="{ Binding images }"
VerticalOptions="Fill"
Aspect="AspectFill" />
</Grid>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
CarouselView does not show anythings . What's the problem ?
Thanks to #Jason and LeoZhu-MSFT
I solved my problem like this :
<CarouselView x:Name="MainCarouselView" ItemsSource="{Binding images}" Grid.Row="1" HeightRequest="150">
<CarouselView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding .}"></Image>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
ItemsSource="{Binding images}" because CarouselView is in CollectionView with ItemsSource="{Binding Home.Post}"

Entity Framework is not creating the database

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.

Entity Framework does not create database

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 ?

Issue with inheritance with WebAPI, OData v3 and BreezeJs

We are using WebAPI 2.2, with OData v3 and BreezeJS and are having an issue when using inheritance, we have a setup along the following lines (simplified obviously for this issue)
We have a Vehicle abstract class and then two other classes (Bus and Car) which inherit from Vehicle, such as:
public abstract class Vehicle
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Bus : Vehicle
{
public int NumberOfSeats { get; set; }
}
public class Car : Vehicle
{
public string Colour { get; set; }
}
We then have an Activity class which can have a single Vehicle (either a Car or a Bus):
public class Activity
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime DueDate { get; set; }
public int VehicleId { get; set; }
public virtual Vehicle Vehicle { get; set; }
}
We would like to be able to query the Activity and expand its Vehicle and get the relevent Car or Bus back, such as https://dummysitename/api/Activities?$expand=Vehicle, which is working fine. We would also like to be able to GET/PATCH/POST to endpoints for Cars and Buses (such as https://dummysitename/api/Cars and https://dummysitename/api/Buses), however we get a 404 when trying to do this.
Our metadata is created by the breeze EdmBuilder. We have tested it not using the EdmBuilder but using the ODataConventionModelBuilder and that works fine for these scenarios, but doesn't obviously work for us in the grander scheme of things as we will be utilizing breeze.js heavily.
Any ideas on why we can't use the Cars and Buses endpoints when using the EdmBuilder would be greatly appreciated.
UPDATE:
It would appear that the issue is being caused by the Vehicle being stipulated on the Activity class. With the Vehicle on the Activity class the EntityContainer section of the metadata looks like this:
<EntityContainer Name="TodoListContext" p5:UseClrTypes="true" xmlns:p5="http://schemas.microsoft.com/ado/2013/11/edm/customannotation">
<EntitySet Name="Activities" EntityType="ODataBreezejsSample.Models.Activity" />
<EntitySet Name="Vehicles" EntityType="ODataBreezejsSample.Models.Vehicle" />
<AssociationSet Name="Activity_Vehicle" Association="ODataBreezejsSample.Models.Activity_Vehicle">
<End Role="Activity_Vehicle_Source" EntitySet="Activities" />
<End Role="Activity_Vehicle_Target" EntitySet="Vehicles" />
</AssociationSet>
</EntityContainer>
however if the Vehicle is removed from the Activity class then that same section looks like this:
<EntityContainer Name="TodoListContext" p5:UseClrTypes="true" xmlns:p5="http://schemas.microsoft.com/ado/2013/11/edm/customannotation">
<EntitySet Name="Activities" EntityType="ODataBreezejsSample.Models.Activity" />
<EntitySet Name="Buses" EntityType="ODataBreezejsSample.Models.Bus" />
<EntitySet Name="Cars" EntityType="ODataBreezejsSample.Models.Car" />
</EntityContainer>
at which point the Bus and Car endpoints become available, however this is not really an option as we require the Activity to contain the base class Vehicle.

Code first is keep creating a database with the fully qualified name of my context

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