Composite Key with EF 4.1 Code First - ef-code-first

I am trying to figure out how to have a composite key using EF code First 4.1 RC.
Currently, I am using the [Key] Data Annotation, but I am unable to specify more than one key.
how would one specify a composite key?
Here is my Example:
public class ActivityType
{
[Key]
public int ActivityID { get; set; }
[Required(ErrorMessage = "A ActivityName is required")]
[StringLength(50, ErrorMessage = "Activity Name must not exceed 50 characters")]
public string ActivityName { get; set; }
}
I need the "ActivityName" to also be a key.
Sure, I can code around this, but thats not good database design.

You can mark both ActivityID and ActivityName properties with Key annotation or you can use fluent API as described by #taylonr.
Edit:
This should work - composite key defined with annotations requires explicit column order:
public class ActivityType
{
[Key, Column(Order = 0)]
public int ActivityID { get; set; }
[Key, Column(Order = 1)]
[Required(ErrorMessage = "A ActivityName is required")]
[StringLength(50, ErrorMessage = "Activity Name must not exceed 50 characters")]
public string ActivityName { get; set; }
}

We don't use the annotations, instead we override the model builder, in which case you can do something like:
modelBuilder.Entity<Activity>().HasKey(a => new { a.ActivityId, a.ActivityName });

Related

Using the same generic foreign key field (KeyId) along with a (Type) field for a single table in EntityFramework

I have a class called Address with the following properties:
public int Id { get; set; }
public string Name { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
public string ZipCode { get; set; }
public int KeyId { get; set; }
public AddressType Type { get; set; }
The plan is for AddressType to be an enum of either: Customer, Vendor, or Location and the KeyId to be the Foreign Key from either the Customer, Vendor, or Location.
Is this something that can be done correctly with Entity Framework or should I be making 3 separate classes CustomerAddress, VendorAddress, LocationAddress.
You need to generate an entity inheritance structure from a single database table. Can achieve that by using a Table per Type approach
TBT Entity Framework
Group the common properties into a "Base" entity, and then use a discriminator (in your case the AddressType) for specializing the object.
I looks like you have three tables Customer, Vendor, or Location and you want to save Address for each.
Then instead of adding AddressType in Address table, you should include AddressID in each table as Foreign key and must have a Address navigation property in each table.

Entity Framework Many To Many allow duplicates

Is it possible to insert duplicate rows in Many to Many relationship? This is my class:
public class EventPaintballBundle
{
[Key, Column(Order = 0)]
public int EventID { get; set; }
[Key, Column(Order = 1)]
public int PaintballBundleID { get; set; }
public virtual Event Event { get; set; }
public virtual PaintballBundle PaintballBundle { get; set; }
[Range(1, Int32.MaxValue)]
public int PersonCount { get; set; }
[Required]
public DateTime Data { get; set; }
}
I want to insert second row of those values. The differences are on Date Date and PersonCount value
EventPaintballBundle xx = new EventPaintballBundle() { PaintballBundleID = 1, EventID = 155, Data = DateTime.Now, PersonCount = 5 };
dc.EventPaintballBundles.Add(xx);
dc.SaveChanges();
I'm getting error while I want to insert a duplicate of two keys.
{"Violation of PRIMARY KEY constraint 'PK_dbo.EventPaintballBundles'.
Cannot insert duplicate key in object 'dbo.EventPaintballBundles'. The
duplicate key value is (155, 1).\r\nThe statement has been
terminated."}
How to solve this problem?
Create a primary key that isn't the combination of :
public int EventID { get; set; }
public int PaintballBundleID { get; set; }
The new primary should be unique and not related to anything that actually exist, this key will exist only to make your model work database wise.
It's a classic mistake : to think your primary key should represent something that exist... NO
I learned it the hard way : even if i think that some combination of existing data will stay forever unique. I don't use it. I ALWAYS create my primary key from my own design, not representing anything real.

What does it mean for 'A Person' has a 'Address object?

In my final ASP.NET assignment, I am instructed to use a code first approach and add the following properties and Model(s) to represent the described changes.
1) A Person 'has a' Address object (This class was given, but I modified adding properties)
2) An Address object has a single property of type string for Email. (I created this class)
namespace ContosoUniversity.Models
{
public class Address
{
[Required]
[RegularExpression(#"[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z] {2,4}")]
public string Email { get; set; }
[Required]
[Compare("Email")]
public string EmailConfirm { get; set; }
}
}
but now I am not sure what he means in the first instruction. I have researched composition, inheritance, and abstract classes but still don't know what I am suppose to do?
How am I suppose to create an Address object in the person class? What does that actually mean? Here is the Person class:
namespace ContosoUniversity.Models
{
public abstract class Person
{
public int ID { get; set; }
[Required]
[StringLength(50)]
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Required]
[StringLength(50, ErrorMessage = "First name cannot be longer than 50 characters.")]
[Column("FirstName")]
[Display(Name = "First Name")]
public string FirstMidName { get; set; }
[Display(Name = "Full Name")]
public string FullName
{
get
{
return LastName + ", " + FirstMidName;
}
}
}
}
It means that there should be a one to one relationship between the person and an address. A Person has one Address.
namespace ContosoUniversity.Models
{
public abstract class Person
{
public int ID { get; set; }
public Address Address {get; set;}
[Required]
[StringLength(50)]
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Required]
[StringLength(50, ErrorMessage = "First name cannot be longer than 50 characters.")]
[Column("FirstName")]
[Display(Name = "First Name")]
public string FirstMidName { get; set; }
[Display(Name = "Full Name")]
public string FullName
{
get
{
return LastName + ", " + FirstMidName;
}
}
}
}
Now you can do something like this (assuming Person wasn't an abstract class)...
Person person = new Person();
person.Address = new Address();
person.Address.Email = "john.doe#example.com";
If your teacher had said something like "a person can have multiple addresses" you could have done something like this (omitted duplicate lines for brevity):
public class Person
{
public IEnumerable<Address> Addresses {get; set;}
public Person()
{
Addresses = new List<Address>(); //initialize with an empty collection
}
}
which would allow you to do this...
Person john = new Person();
Address home = new Address(){Email = "john.doe#example.com"}; //create a new address and set its Email property to a value in a single line
Address work = new Address(){Email = "johndoe#work.com"};
john.Addresses.Add(home); //Add the address to the Addresses collection of john
john.Addresses.Add(work);

Allow nullable strings and List<string> as datatype in Entity Framework Model in ASP.NET MVC

I have a model class defined as:
public class EventReg
{
public int ID { get; set; }
[Display(Name = "Event Date")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime EventDate { get; set; }
[Display(Name = "Event Time")]
[DataType(DataType.Time)]
[DisplayFormat(DataFormatString = "{0:t}", ApplyFormatInEditMode = true)]
public DateTime EventTime { get; set; }
public List<string> HashTags { get; set; }
public string Category { get; set; }
[Display(Name = "Registered by")]
public string UniqueId { get; set; }
public float Latitude { get; set; }
public float Longitude { get; set; }
public string Description { get; set; }
}
Questions:
Now I don't really know that whether there will be a category and Hash Tags for every event. So, I want to register these fields as Nullable but when I defined these fields as System.Nullable for category or System.Nullable > for HashTags, there was an error saying "The type string/List<string> must be non-nullable value type in order to use it as a parameter 'T' in the generic type or method'System.Nullable<T>'". How to counter this error?
I wanted to be able to update the database schema later so used package manager console(add-migration intial command) to create an *datetime_initial.cs* file which will be executed everytime I call update-database. But due to some reason the field HashTags was not listed in the datetime_initial.cs file created. Why?
Try this:
public class EventReg
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] // !!!
public int ID { get; set; }
[Display(Name = "Event Date")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime? EventDate { get; set; } // added "?"
[Display(Name = "Event Time")]
[DataType(DataType.Time)]
[DisplayFormat(DataFormatString = "{0:t}", ApplyFormatInEditMode = true)]
public DateTime? EventTime { get; set; } // added "?"
public virtual ICollection<string> HashTags { get; set; } // changing List to ICollection virtual
public string Category { get; set; }
[Display(Name = "Registered by")]
public string UniqueId { get; set; }
public float Latitude { get; set; }
public float Longitude { get; set; }
public string Description { get; set; }
}
Also, feel free to get rid of EventDate and EventTime, because DateTime is holding date and time:
public DateTime? EventDateStamp { get; set; }
You can define your own read-only properties if you need a time or data. But it's not recommended to do this in model, because it's considered as a good practice if you keep your model consistent, and when your model is not dependent on how are you going to show it to the user. You can use view models for this purpose and use Automapper tool for that.
One more advice is to get rid of DateTime and use DateTimeOffset:
public DateTimeOffset? EventDateStampUtc { get; set; }
with universal date and time:
model.EventDateStampUtc = DateTimeOffset.Utc;
The main benefit of using UTC time is that you don't need to think about date and time if you have multiple servers, located in other countries, with different times and timezones. Also, you and your customers are not dependent on the server's timezone.
And since this question is about ASP.NET MVC, I can suggest you may want to display this date and time later in your view. I recommend to use wonderful moment.js library on the client side for this purpose.
...which will be executed everytime I call update-database...
Use Seed method in your Migrations\Configuration.cs for this purposes:
protected override void Seed(MyContext context)
{
context.MyEntities.AddOrUpdate(
e => e.Key,
new MyEntity { aa = 1, bb = 2, key = "unique-001" },
new MyEntity { aa = 11, bb = 22, key = "unique-002" }
);
}
Some useful options in Configuration constructor:
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true; // take care!
}

How to set a Foreign Key relationship manually in LINQ To SQL

I've been working through the book Pro ASP.NET MVC 2 Framework by Steven Sanderson. So far it's been phenominal... just when i think I know a decent amount I find a book that shows me just how little I know.
One of the things I know little about is how to use LINQtoSQL. In Steven's book, chapters 4-6 create a very nice little shopping cart. I went through the tutorial and got everything working. Now I want to modify the cart to use a Category table instead of storing the category name as a varchar in the Product table.
Here's the Product table object with my changes to have CategoryID as a foreign key relationship to the Categories Table.
[Table(Name="Products")]
public class Product
{
[HiddenInput(DisplayValue=false)]
[Column(IsPrimaryKey=true, IsDbGenerated=true, AutoSync=AutoSync.OnInsert)]
public int ProductID { get; set; }
[Required(ErrorMessage="Please enter a product name")]
[Column] public string Name { get; set; }
[Required(ErrorMessage="Please enter a description")]
[DataType(DataType.MultilineText)]
[Column] public string Description { get; set; }
[Required]
[Range(0.01, double.MaxValue, ErrorMessage="Please enter a positive price")]
[Column] public decimal Price { get; set; }
[Required(ErrorMessage="Please enter a category")]
[Column] public int CategoryID { get; set; }
internal EntityRef<Category> _category;
[System.Data.Linq.Mapping.Association(ThisKey = "CategoryID", Storage = "_category")]
public Category Category {
get { return _category.Entity; }
internal set { _category.Entity = value; CategoryID = value.CategoryID; }
}
[Column] public byte[] ImageData { get; set; }
[ScaffoldColumn(false)]
[Column] public string ImageMimeType { get; set; }
And here is my Category class
[Table(Name="Categories")]
class Category
{
[Column(IsPrimaryKey=true, IsDbGenerated=true, AutoSync=AutoSync.OnInsert)]
internal int CategoryID { get; set; }
[Column]
public int ParentCategoryID { get; set; }
[Column]
[Required]
public string Name { get; set; }
}
When I tried to build this code, i got an error that I don't understand:
Inconsistent accessibility: property type 'SportsStore.Domain.Entities.Category'
is less accessible than property 'SportsStore.Domain.Entities.Product.Category'
What does that mean / How would I fix this?
Your class "Categroy" is less visibly then "Product". "Product" has a public Property "Category" which is public. This is the "Inconsistent accessibility".
You have to declare your class "Category" public like "Product"

Resources