Entity Framework and Models with Simple Arrays - entity-framework

This is my model class.
public class Lead
{
private readonly ObservableCollection<String> m_tags = new ObservableCollection<string>();
public int LeadId { get; set; }
public string Title { get; set; }
public ObservableCollection<String> Tags { get { return m_tags; } }
}
Does Entity Framework offer a way to represent this using either Model-First or Code-First?
EDIT: I'm looking for a way to do this without changing the public API of the model. The fact that there is some sort of Tags table shouldn't be visible to the downstream developer.

Since your model has to be represented in a relational way, you can only use primitive types (that have an equivalent in a SQL DB) or other entities within a entity definition - that means the tags are represented by their own entity. In your case it would be something like this using Code first approach:
public class Lead
{
public int LeadId { get; set; }
public string Name { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
public class Tag
{
public int TagId { get; set; }
public string Name { get; set; }
}
public class SomeContext : DbContext
{
public DbSet<Lead> Leads { get; set; }
public DbSet<Tag> Tags { get; set; }
}
This (by default) will be represented in the database as a table Leads, a table Tags, and a relationship table LeadTags that only contains {LeadId, TagId} pairs.

Related

How can I add two property in my model in EF code first from one model?

I want to add two properties from the city model:
after migration this error shows up:
Unable to determine the relationship represented by navigation
'City.Orders' of type 'ICollection'. Either manually configure
the relationship, or ignore this property using the '[NotMapped]'
attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
here is my code :
public class Order
{
public virtual City FromCity { get; set; }
public virtual City ToCity { get; set; }
}
public class City
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
I suppose your model is more complicated than just FromCity and ToCity because I don't think it's a good idea to store such information in a different table. Yet, You can use inheritance in this case.
The table-per-hierarchy (TPH) pattern is used by default to map the inheritance in EF. TPH stores the data for all types in the hierarchy in a single table.
However, for your scenario, you can have a base class that holds all related attributes.
public class CityBase
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
}
Then suppose you need two entities as per your scenario:
public class FromCity : CityBase
{
public virtual ICollection<Order> Orders { get; set; } = null!;
}
public class ToCity : CityBase
{
public virtual ICollection<Order> Orders { get; set; } = null!;
}
And the order entity:
public class Order
{
public int Id { get; set; }
public string OrderTitle { get; set; } = string.Empty;
public virtual FromCity FromCity { get; set; } = null!;
public virtual ToCity ToCity { get; set; } = null!;
}
This approach can solve your problem with a One-to-Many relationship between Orders and FromCity, ToCity as per below diagram:

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; }
}
}

Entity Framework: Why is a property of type array of objects not persisted to DB?

I have two entities where one has a one to many relationship to the other. Example:
public class Question
{
public int Id { get; set; }
public string Text { get; set; }
public Answer[] Answers { get; set; }
}
public class Answer
{
public int Id {get; set; }
public string Text { get; set; }
}
Using EF6 Code First I've setup this simple DbContext:
public class MyContext : DbContext
{
public MyContext()
{
Database.SetInitializer<MyContext>(new DropCreateDatabaseAlways<MyContext>());
}
public DbSet<Question> Questions { get; set; }
public DbSet<Answer> Answers { get; set; }
}
What I end up with in the DB are two similarly structured tables (int PK column and varchar column) and no representation of the "one Question has many Answers" relationship that I intended with the Question.Answers property.
Why doesn't EF Code First map the relationship and how can I fix this?
Entity Framework doesn't support mapping navigation properties of bare Array types. The property has to be of Type that implements the ICollection<T> interface in order to be mapped.
Try to change your code as follows:
public class Question
{
public int Id { get; set; }
public string Text { get; set; }
public virtual ICollection<Answer> Answers { get; set; }
}
And when initializing Answers, set it to a HashSet or List:
this.Answers = new List<Answer>();

Entity Framework DB First: Convert Associative Table to Navigation Properties

I am using Entity Framework Database First, but I would like to replicate the following behavior from the Code First paradigm:
In Entity Framework Code First, you can do something along these lines:
public class Thing
{
public int ID { get; set; }
ICollection<Stuff> Stuffs { get; set; }
}
public class Stuff
{
public int ID { get; set; }
ICollection<Thing> Things { get; set; }
}
And the database will generate and Associative table to represent the many to many relationship.
I'm using Database First with a legacy database. I pulled in the entities and it included the associative table representing a many-to-many relationship between two of our tables.
Since the associative table is included as an entity, the navigation properties are as such:
public class Thing
{
public int ID { get; set; }
public ICollection<ThingStuff> ThingStuffs { get; set; }
}
public class ThingStuff
{
public int ThingID { get; set; }
public int StuffID { get; set; }
ICollection<Thing> Things { get; set; }
ICollection<Stuff> Stuffs { get; set; }
}
public class Stuff
{
public int ID { get; set; }
public ICollection<ThingStuff> ThingStuffs { get; set; }
}
So to navigate, I have to:
var stuff = Thing.ThingStuffs.Select(ts => ts.Stuff);
Instead of:
var stuff = Thing.Stuffs;
So The Question Is:
Is there any way to drop the entity representing the association (ThingStuff) and tell EntityFramework about the existing table to create the many-to-many navigation properties?
Wouldn't it be better if you map your composite keys, as stated in the fluent api documentation? http://msdn.microsoft.com/en-us/data/jj591617.aspx

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; }
}