Additional virtual/navigation properties - entity-framework

I have the following model:
public class Useraccount
{
public int Id { get; set; }
public virtual ICollection<Task> Tasks { get; set; }
}
The tasks collection is filled by the entity framework via the task entity. This is working without problems.
Now I'd like to have an additional virtual property so the class would look like this:
public class Useraccount
{
public int Id { get; set; }
public virtual ICollection<Task> Tasks { get; set; }
public virtual ICollection<Task> FinishedTasks { get; set; }
}
The FinishedTasks property is the same like Tasks, but it only has tasks which are finished (which have the statusId = 1 for example).
Is it possible to do that with the EF? How?

Define the property like this:
public class Useraccount
{
public int Id { get; set; }
public virtual ICollection<Task> Tasks { get; set; }
[NotMapped]
public IEnumerable<Task> FinishedTasks
{
get
{
return Tasks.Where(t => t.Finished);
}
}
}
NotMapped attribute tells the EF that this property is not mapped to a database column (see this page for more information).
There is no need to make it virtual (unless you exactly know why) because EF is not going to override it. Also the set accessor should not be present, because it is actually a calculated property.

Related

Scaffolding MVC Controller - how to indicate dataValueField and dataTextField?

One of the overload methods of SelectList (from the Microsoft.AspNetCore.Mvc.Rendering namespace) is defined as:
public SelectList(IEnumerable items, string dataValueField, string dataTextField);
When I scaffold an "MVC Controller with view, using Entity Framework" and I create my CRUD pages, I may see the following method inside of my Controller:
public IActionResult Create()
{
ViewData["Continent"] = new SelectList(_context.Continent, **"ContinentID", "ContinentID"**);
ViewData["Country"] = new SelectList(_context.Country, **"CountryID", "CountryName"**);
return View();
}
The field supplied to the dataTextField parameter is different between Continent/Country. How does MVC/EntityFramework decide which field to supply to dataTextField when scaffolding a Controller? Is there something in the individual models or in the DbContext that I am overlooking? I'd like for the dataTextField of Continent to be "ContinentName" so that I don't have to change it manually in the future when I need to delete and then re-scaffold the Controller.
Edit:
Here are the model definitions:
The Model of the Controller that I posted above:
using System;
using System.Collections.Generic;
namespace Project.Models
{
public partial class ProjectForm
{
public int ProjectFormID { get; set; }
public int ContinentID { get; set; }
public int CountryID { get; set; }
public virtual Continent ContinentNavigation { get; set; }
public virtual Country CountryNavigation { get; set; }
}
}
The one that displays the "CountryName" in the dataTextField the way that I want to see it:
namespace Project.Models
{
public partial class Country
{
public int CountryID { get; set; }
public string CountryName { get; set; }
public virtual ICollection<ProjectForm> ProjectForm { get; set; }
}
}
The one that displays the "ContinentID" in the dataTextField the way that I do NOT want to see it:
namespace Project.Models
{
public partial class Continent
{
public int ContinentID { get; set; }
public string ContinentName { get; set; }
public virtual ICollection<ProjectForm> ProjectForm { get; set; }
}
}
There is nothing obviously different to me in the model definitions unfortunately.
I stumbled across this post today (a bit late), but see it still hasn't been answered.
While I can't say why the scaffolding chose to use one field over another in your scenarios (unless you initially had your class/model written differently the last time you cleaned/built your project), I can say how to force it to use a specific column.
Add the DisplayColumn attribute to your class. You will need to rebuild before scaffolding again for the change to take.
namespace Project.Models
{
[DisplayColumn("ContinentName")]
public partial class Continent
{
public int ContinentID { get; set; }
public string ContinentName { get; set; }
public virtual ICollection<ProjectForm> ProjectForm { get; set; }
}
}

The entity type 'Program' requires a primary key to be defined

I am trying to make a simple website that tracks students, programs, and classes. I've created the entities and I'm getting an error when trying to add the migration.
"The entity type 'Program' requires a primary key to be defined."
I have tried using the [Key] attribute and there is an Id field. The other table was created just fine. What else should I try?
Here is the problem class:
public class Program
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool UseRanks { get; set; }
}
Here is another table that I had no problems creating a migration for:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string CellPhone { get; set; }
public string HomePhone { get; set; }
public string WorkPhone { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public DateTime BirthDate { get; set; }
}
Here is what is in my ApplicationDbContext class:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
//public DbSet<Attendance> Attendances { get; set; }
public DbSet<Person> People { get; set; }
public DbSet<Bill> Bills { get; set; }
//public DbSet<Session> Sessions { get; set; }
public DbSet<Program> Programs { get; set; }
}
I've commented out the other entities because I was trying to add them one at a time. Trying to add a migration with all the entities resulted in the same error with the same specific class.
Complete shot in the dark, but based on the name of this class, I'm guessing you're referencing the wrong Program. Make sure that your DbSet<Program> is actually using your Program entity and not something like the Program class used at the console app level. You'll likely need to explicitly use the namespace, i.e. DbSet<MyApp.Models.Program>.
You might also consider changing the name of the class to remove any chance of ambiguity. There's some class names that are just going to wreck havoc trying to use them because they'll conflict with framework stuff constantly. It's usually more hassle than it's worth just to have that particular name. Program is one of those.
You can try to use this way:
public class Program
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool UseRanks { get; set; }
}
Adding [Key] attribute to the Id property.
In the file ApplicationDbContext.cs, you can override OnModelCreating method:
public DbSet<Program> Programs { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Program>().ToTable("Programs").HasKey(x => x.Id);
}

Incorrect Domain model with ef

I have a little problem with Entity Framework when trying to model the real life
problem.
I have 2 entity like this :
public class Person
{
public int Id { get; set; }
public ICollection<Task> Tasks{ get; set; }
}
public class Task
{
public int Id { get; set; }
public Person Assignee{ get; set; }
public Person Assigner{ get; set; }
}
but if I want to use Entity framework,it forces me to change my model like this that it is different from real life !!
public class Person
{
public int Id { get; set; }
public ICollection<Task> AssigneesTasks{ get; set; }
public ICollection<Task> AssignerTasks{ get; set; }
}
(i just have single one-to-many relation in fact)
what is the solution to keep my model according to real life model?
Well you might want to know what tasks a person has assigned to them, and what tasks they have assigned to others. If you don't want both Navigation properties you don't need them in EF. But you do need to tell EF which relationship the Navigation Property is for. EG:
public class Person
{
public int Id { get; set; }
[InverseProperty("Assignee")]
public ICollection<Task> Tasks { get; set; }
}
public class Task
{
public int Id { get; set; }
public Person Assignee { get; set; }
public Person Assigner { get; set; }
}

Entity framework Database First & EF Code First get Relation Object By ID

in EF Database First when change ForeignKey(CommodityGroupID) automatic Get CommodityGroup for Commodity object, But in EF Code First(4.3.1) not doing.
public class Commodity
{
public int CommodityID { get; set; }
public string MadeBy { get; set; }
public decimal ServiceTimePrice { get; set; }
public decimal QCPrice { get; set; }
public int ServicePoint { get; set; }
public string Note { get; set; }
public int CommodityGroupID { get; set; }
[ForeignKey("CommodityGroupID")]
public virtual CommodityGroup CommodityGroup { get; set; }
}
public class CommodityGroup
{
public int CommodityGroupID { get; set; }
public string CommodityGroupName { get; set; }
public virtual ICollection<Commodity> Commodities { get; set; }
}
this Property defined in Edmx file (database first), i Should define this code in ef code first?
[BrowsableAttribute(false)]
[DataMemberAttribute()]
public EntityReference<CommodityGroup> CommodityGroupReference
{
get
{
return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<CommodityGroup>("GaamRepairModel.FK_Commodity_CommodityGroup", "CommodityGroup");
}
set
{
if ((value != null))
{
((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedReference<CommodityGroup>("GaamRepairModel.FK_Commodity_CommodityGroup", "CommodityGroup", value);
}
}
}
It sounds like you're wanting a change tracking proxy. You want the CommodityGroup navigation property to update automatically when the FK is changed correct?
See this post on MSDN for details about the change tracking proxy.
This post on MSDN shows some code on how to test of your proxy object is being created properly.
Is this a new object? If so, you'll need to call the CreateObject function on your DbSet, not use the New Commodity().

EF Code First: Treating entity like a complex type (denormalization)

I'm using EF 4.1 Code First, and I'm making a configurable utility for parsing/importing large delimited files. Each row in the file may contain data for several entities.
The exact data and layout for the file will be unknown at build time (it's configured differently for each client), so I'm making it configurable.
Example model (simplified)
public class Contact {
public int Id { get; set;}
public string Name { get; set; }
}
public class Account {
public int Id { get; set; }
public decimal Balance { get; set; }
public bool IsOpen { get; set; }
}
Depending on the client, a file may contain contact info, account info, or both. Because of the size of these files (tons of records), we have to use SqlBulkCopy to do the data loading. It's also unknown at compile time exactly what rules will be run against the data (validation changes by client, etc.)
I want to have a table and class, like ImportRecord, to hold the imported data. My current working class is like:
public class ImportRecord {
public string Contact_Name { get; set; }
public decimal Account_Balance { get; set; }
public bool Account_IsOpen { get; set; }
}
The issue here is that as we add/change fields in the model classes, the ImportRecord has to get changed also -- it's duplicative/less than ideal. It's somewhat important to me that the import data resides in a single table to simplify the SqlBulkCopy import.
My ideal ImportRecord class would look like this:
public class ImportRecord {
public Contact Contact { get; set; }
public Account Account { get; set; }
}
But that would just create a table with two foreign keys (aside from complaining about no FK properties). Is there a way to have the entity classes behave more like a denormalized, keyless, complex type for the ImportRecord? Am I going about this entirely wrong?
Thanks!
Entity cannot be nested and in the same time complex type cannot have entity key so you cannot use one instead of other but you can try this little cheat. I just tested that it at least creates correct database structure:
public class Context : DbContext
{
public DbSet<Account> Accounts { get; set; }
public DbSet<Contact> Contacts { get; set; }
public DbSet<ImportRecord> ImportRecords { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ComplexType<ContactBase>();
modelBuilder.ComplexType<AccountBase>();
}
}
public class ContactBase
{
public string Name { get; set; }
}
public class AccountBase
{
public decimal Balance { get; set; }
public bool IsOpen { get; set; }
}
public class Contact : ContactBase
{
public int Id { get; set; }
}
public class Account : AccountBase
{
public int Id { get; set; }
}
public class ImportRecord
{
public int Id { get; set; }
public ContactBase Contact { get; set; }
public AccountBase Account { get; set; }
}