EF4 CTP5 - Map foreign key without object references? - entity-framework-4

I feel like this should have a simple answer, but I can't find it.
I have 2 POCOs:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Product
{
public int Id { get; set; }
public int CategoryId { get; set; }
}
Notice that there are no object references on either POCO. With Code-First, how do I make EF4 CTP5 define a relationship between the two database tables?
(I know this is an unusual scenario, but I am exploring what's possible and what's not with Code-First)

No, this is not possible. As you can see below, all of the fluent API methods for setting up associations require specifying the Navigation Property as their parameter.
HasMany<TTargetEntity>(Expression<Func<TEntityType, ICollection<TTargetEntity>>> navigationPropertyExpression)
HasOptional<TTargetEntity>(Expression<Func<TEntityType, TTargetEntity>> navigationPropertyExpression)
HasRequired<TTargetEntity>(Expression<Func<TEntityType, TTargetEntity>> navigationPropertyExpression)

Is there any particular reason you don't want to use object references? It looks very elegant to use them:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
public int Id { get; set; }
public Category Category { get; set; }
}
And you can still access the Category Id via your product as product.Category.Id.

Related

Two optional one-to-one EF relationship

Is it possible to build two optional one-to-one relationship in SQL?
I'd like to have:
public class EventInvoice
{
[Key]
public int ID { get; set; }
[ForeignKey("SZ_Event")]
public Nullable<int> SZ_EventID { get; set; }
public virtual SzopbudkaEvent SZ_Event { get; set; }
[ForeignKey("UP_Event")]
public Nullable<int> UP_EventID { get; set; }
public virtual Event UP_Event { get; set; }
}
public class Event
{
[Key]
public int EventID { get; set; }
public virtual EventInvoice EventInvoice { get; set; }
}
public class SzopbudkaEvent
{
[Key]
public int ID { get; set; }
public virtual EventInvoice EventInvoice { get; set; }
}
My invoice can be combined only with one of those objects (Event or SzopbudkaEvent). Is it possible to use it like this or I have to write something different?
You can do this but there are two things to bear in mond.
If the constraint is only one of the FK's can exist, then in the database the FK columns on the EventInvoice tale must be nullable. You've got this but I thought I'd emphasise it.
If there is also a constraint that there must be one of them (missing both is not allowed) then you have to work out how to validate that constraint. In the DB I'd use a trigger fir insert, update that raises an exception if both are null. I'd match that in code with a pre-save check: this describes implementing interface IValidatableObject with a Validate method which EF will call when the object is affected by SaveChanges.

Entity Framework defining tables in db context

I am buys designing the model below:
public class LogModel
{
public class UserActivityLogs
{
[Key]
public int id { get; set; }
//Id of the user
public string userId { get; set; }
//Time of the log
public DateTime time { get; set; }
public LogActions action { get; set; }
}
// Types of actions to log
public class LogActions
{
[Key]
public int id { get; set; }
public string name { get; set; }
public string description { get; set; }
}
}
Now what I would like to know is do I need to add a table in the context for Logactions as well as UserActivityLogs or will EF see that the two tables are linked and create the log action table automatically?
Also have I specified my relationships correctly? What I was aiming for is that I can define multiple types of Logactions and then a userlog will then have a single log action associated to it.
First, don't use nested classes, it's a needless complication. Use namespaces to organize classes.
Second, don't use plural names for classes. One instance of class represents one entity. Also, use CamelCase names for properties.
Third, yes, Entity Framework will be aware of the associations between the two classes and create a database model with two tables and a foreign key.
So this leaves you with:
namespace MyApp.LogModel
{
public class UserActivityLog
{
[Key]
public int Id { get; set; }
public string UserId { get; set; }
public DateTime Time { get; set; }
public LogAction LogAction { get; set; }
}
public class LogAction
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
}

ASP.NET MVC 3 EF Code First - How do I make a model that optionally refers to a parent of its own type?

I'm trying to create a model that can optionally refer to a parent of the same type, for example:
public class Category
{
public virtual long CategoryID { get; set; }
public virtual Category? ParentCategory { get; set; }
public virtual int UserID { get; set; }
public virtual string Name { get; set; }
}
As you can see there is an optional member called ParentCategory that is optional and refers to a class of type Category (i.e. the same type). As I'm sure you can guess, I'm trying to create a simple Category tree, where the root node(s) will not have a parent.
This results in the following error when the Entity Framework tries to create the database:
"The ForeignKeyAttribute on property 'ParentCategoryID' on type 'MyProject.Models.Category' is not valid. The navigation property 'Category' was not found on the dependent type 'MyProject.Models.Category'. The Name value should be a valid navigation property name."
I also tried this:
public class Category
{
public virtual long CategoryID { get; set; }
[ForeignKey("Category")]
public virtual long? ParentCategoryID { get; set; }
public virtual int UserID { get; set; }
public virtual string Name { get; set; }
}
But again this resulted in the same error.
Is it possible to model this using EF Code First? Its easy to model it int he database if I were to create the database manually.
Thanks in advance
Ben
Your first example wouldn't even compile because T?, a shortcut for Nullable<T> can only be applied to value types.
The following works fine here:
public class Category
{
public virtual long CategoryID { get; set; }
public virtual Category ParentCategory { get; set; }
}
Now, this will use an ugly name by default for the FK, ParentCategory_CategoryID.
This is a way to get a nicer name, plus some flexibility when using it:
public class Category
{
public virtual long CategoryID { get; set; }
[ForeignKey("ParentCategoryID")]
public virtual Category ParentCategory { get; set; }
public virtual long? ParentCategoryID { get; set; }
}

Alternative for enum - when seeding a database

I am right now in the design phase of a new app and am doing some research. I came across the CodeFirst approach of EF 4.3 and really liked it.
However there is one design goal, I am not sure how to achieve.
Let say I have a task class:
public class TaskModel
{
public int ID { get; set; }
public string Name { get; set; }
public TaskType Task { get; set; }
}
public enum TaskType
{
Sales = 0,
Marketing = 1,
CustomerService = 2
}
I know that enums are currently not supported in EF 4.3. Hence this code would not even generate a proper database model. However I don't even need enums. Since what if the user would like to add a new TaskType at runtime?
Hence I think its best to have the TaskType as a class, which would become a table in itself and the user could add more entries. But how do I make them map together?
In such case it is common one-to-many relation:
public class TaskModel
{
public int ID { get; set; }
public string Name { get; set; }
public virtual TaskType Task { get; set; }
}
public class TaskType
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<TaskModel> TaskModels { get; set; }
}

How to create One-to-many relationship in Entity Framework 4.1 using Code First and Data Annotations?

I'm struggling with creating a simple one-to-many relationship using Code First in EF. I want it to generate daatabase for me but couldn't figure out how to write these classes so it would create it.
I have these classes:
public class Book
{
public int ID { get; set; }
public string Author { get; set; }
public ICollection<Page> Pages { get; set; }
}
public class Page
{ [Key]
public int BookID { get; set; }
public Book Book { get; set; }
public string OtherField { get; set; }
}
But I get error while it ties to generate database:
Unable to determine the principal end of an association between the types 'MvcApplication1.Models.Page' and 'MvcApplication1.Models.Book'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations
I just want to generate two simple tables, "Book" with ID as primary key, and Page with BookID as a primary and foreign key. It really should be simple but I just can't figure it out.
But that is not one-to-many relationship. That is one-to-one relation ship which says that each book has exactly one page. The error says that it cannot determine if the book or the page is principal in the one-to-one relation.
You must modify your entities like this:
public class Book
{
public int ID { get; set; }
public string Author { get; set; }
public virtual ICollection<Page> Pages { get; set; }
}
public class Page
{
public int ID { get; set; }
public int BookID { get; set; }
public virtual Book Book { get; set; }
public string OtherField { get; set; }
}

Resources