I'm using CTP5 of the code first. Take the following simple class and associated DbContext
public class Test
{
public Test()
{
Keywords = new Collection<string>();
}
public int Id { get; set; }
public string Name { get; set; }
public ICollection<string> Keywords { get; set; }
}
public class TestDbContext : DbContext
{
public TestDbContext()
{
Database.Delete();
Database.CreateIfNotExists();
}
public DbSet<Test> Tests { get; set; }
protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
The type 'System.Collections.Generic.ICollection' must be a non-nullable value type in order to use it as parameter 'T'
in the generic type or method 'System.Data.Entity.ModelConfiguration.Configuration.Types.StructuralTypeConfiguration
.Property(System.Linq.Expressions.Expression>)'
Any ideas how to create the necessary table relationships between test class and the keywords property?
Add class Keyword and change ICollection<string> Keywords {get; set;} to ICollection<Keyword> Keywords {get; set;}
public class Keyword
{
public string Data {get;set;}
}
and code model creating like this:
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Keyword>()
.HasKey(x => x.Data);
base.OnModelCreating(builder);
}
Just imagine, that you have 2 collections 1 - Keywords, 2 - Tags. Your realization would map it to same table, because in ORM mapping type defines entity. And both Keyword and Tag are of type string. So to split this entities you should split types.
Related
I am new to ASP.NET MVC. I was trying to build a model as follows (assume the syntax is alright). I wanted to know how to bind and save an object that contains list of objects. For eg. in the following code, I want to save an object of type SchoolGrade to the database (it works fine if it does not contain List<Chapter> or create a separate dbset for Chapter and link by Id).
The SchoolGrade object has 2 lists of the type List<Chapter>, one for physics and another for math. Assuming I am populating the list correctly for physics and math, I am not sure how to save the context as a whole for SchoolGrade which includes both the lists.
Note: I am using 2 List<Chapter> instead of having one List<Chapter> and having a type in the Chapter class because, I want to dynamically add and remove chapters for physics and math in different sections of HTML to keep a clean design.
Code snippet:
namespace School.Models
{
public class SchoolGrade
{
public Guid SchoolGradeID {get; set;}
public string SchoolGradeName {get; set;} //eg. 8th Grade
public List<Chapter> Physics {get; set;} //eg. List of chapters for physics course
public List<Chapter> Maths {get; set;} //eg. List of chapters for maths course
public SchoolGrade()
{
Physics = new List<Chapter>();
Maths = new List<Chapter>();
}
}
public class Chapter
{
public string ChapterName {get; set;}
public string ChapterContent {get; set;}
}
}
namespace School.Controllers
{
public class SchoolGradesController : Controller
{
private SchoolGradeContext db = new SchoolGradeContext();
}
public ActionResult Create()
{
var schoolGrade = new SchoolGrade();
return View(job);
}
[HttpPost]
public ActionResult Create(SchoolGrade schoolGrade)
{
if (ModelState.IsValid)
{
db.SchoolGrades.Add(schoolGrade);
db.SaveChanges();
}
return View(schoolGrade);
}
}
namespace School.DAL
{
public class SchoolGradeContext : DbContext
{
public PipelineContext() : base("PipelineContext")
{
}
public DbSet<SchoolGrade> SchoolGrades { get; set; }
}
}
Could you please point out the best way to go about following design? I tried browsing many topics relating to this but none had provided any context regarding saving the changes to a db (without using a separate dbset).
Thanks for helping in advance.
Try out the ForeignKey attribute on the Chapter class with a field to carry the SchoolGradeId.
For example:
public class Chapter
{
public string ChapterName {get; set;}
public string ChapterContent {get; set;}
[ForeignKey("SchoolGrade")]
public Guid SchoolGradeID {get; set;}
}
I think you should rather consider involving inheritance in your design, having just one collection of Chapters on SchoolGrade results in cleaner design (you don't need to add a new property for each new Chapter) and you will get rid of problems regarding mapping with EF.
public class Chapter
{
public int Id { get; set; }
...
}
public class PhysicsChapter : Chapter
{
...
}
public class MathsChapter : Chapter
{
...
}
public class SchoolGrade
{
public int Id { get; set; }
public List<Chapter> Chapters { get; set; }
...
}
public class SchoolGradeContext : DbContext
{
public SchoolGradeContext() : base("SchoolGradeContext")
{
}
public DbSet<SchoolGrade> SchoolGrades { get; set; }
public DbSet<Chapter> Chapters { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Chapter>().Map<PhysicsChapter>(m => m.Requires("ChapterTypeId").HasValue(1));
modelBuilder.Entity<Chapter>().Map<MathsChapter>(m => m.Requires("ChapterTypeId").HasValue(2));
}
}
Which would require having some discriminator column ChapterTypeId on your Chapter table.
I create a project in MVC 5 with entity framework 6. I am using code first approach. I want in one of the models define a different name for the table then the default. For that I use the System.ComponentModel.DataAnnotationsname space and define the class like this:
[Table(Name="Auditoria")]
public class AuditoriaDAL
{
[Key]
public int AuditoriaId { get; set; }
...
}
Running the project I get a database with a table with the name AuditoriaDALs. Why the table have this name a not the name that I define?
You are referencing the System.Data.Linq.Mapping.Table attribute when you need to reference System.ComponentModel.DataAnnotations.Schema.Table. So either do this:
[System.ComponentModel.DataAnnotations.Schema.Table("Auditoria")]
public class AuditoriaDAL
{
[Key]
public int AuditoriaId { get; set; }
...
}
Or better yet:
using System.ComponentModel.DataAnnotations.Schema;
...
[Table("Auditoria")]
public class AuditoriaDAL
{
[Key]
public int AuditoriaId { get; set; }
...
}
https://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations(v=vs.110).aspx
you can set TableName like below :
public class MyContext : DBContext
{
public virtual DbSet<AuditoriaDAL> Auditorias { get; set; }
}
Or in OnModelCreating :
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<AuditoriaDAL>().ToTable("Auditorias");
}
The name= isn't necessary. You should try [Table("Auditoria")].
I find thousands examples for codefirst relations, but i can't do work my sample !
Many errors like this:
The ForeignKeyAttribute on property 'LanguageID' on type 'BL.Objects.User' is not valid. The navigation property 'Language' was not found on the dependent type 'BL.Objects.User'. The Name value should be a valid navigation property name.
and same same same...
I really want to load language association with user. (en, ru, es)
public abstract class BaseUser : FinanceBase<int>, IUser
{
[ForeignKey("Language")]
public int LanguageID { get; set; }
[ForeignKey("LanguageID")]
public virtual Language Language { get; private set; }
}
public class User : BaseUser
{
public override void GenerateID()
{
...
}
}
public abstract class BaseLanguage : FinanceBase<int>, ILanguage
{
#region Implementation of ILanguage
public string Code { get; set; }
public string Fullname { get; set; }
public string ImagePath { get; set; }
#endregion
}
public class Language : BaseLanguage
{
public override void GenerateID()
{
}
}
public class FinanceDatabaseContext : DbContext
{
public FinanceDatabaseContext()
{
Database.SetInitializer(new FinanceContextInitializer());
}
public DbSet<User> Users { get; set; }
public DbSet<Language> Languages { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Users");
}).HasKey(x => x.ID).HasRequired(x => x.Language).WithMany().HasForeignKey(x => x.LanguageID);
modelBuilder.Entity<Language>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Languages");
}).HasKey(x => x.ID);
base.OnModelCreating(modelBuilder);
}
}
public class FinanceContextInitializer : DropCreateDatabaseIfModelChanges<FinanceDatabaseContext>
{
protected override void Seed(FinanceDatabaseContext context)
{
context.Database.ExecuteSqlCommand("ALTER TABLE Users ADD CONSTRAINT uc_Language UNIQUE(LanguageID)");
}
}
Thanks !
You don't need to use foreign key for LanguageID
public int LanguageID { get; set; }
[ForeignKey("LanguageID ")]
public virtual Language Language { get; private set; }
Add a virtual navigation field to your User table for language if it isnt already there.
Ie you have LanguageId and Language in the POCO class User.
The alternative is a navigation field in Language Class back to User,
ie Public virtual List Users
But lets stick to Users having BOTH virtual navigation property and Foreign Key Id field.
... the rest of User.....
public int LanguageId
// nav relationship
public virtual Language Language { set; get; }
// Now the FK declaration as you described should work in fluent API...
// Has required NAVIGATION property, its 1 to many and the I have a field for this FK value called X
modelBuilder.Entity<User>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Users");
}).HasKey(x => x.ID).HasRequired(x => x.Language).WithMany().HasForeignKey(x => x.LanguageID);
Solved. My Navigation property Language has private setter
[ForeignKey("LanguageID")]
public virtual Language Language { get; private set; }
I using "Entity Framework DbContext" at the moment I have got exception towars.dbo was not found. This is very strange because in my website I all the time ask about towar.dbo but no towars.dbo Do you know where is a problem?
- InnerException {"Invalid object name 'dbo.Towars'."} System.Exception {System.Data.SqlClient.SqlException}
My all things about Towar (of course different place in my program):
public class ProductController : Controller
{
//
// GET: /Product/
public ITowarRepository repository;
public ProductController(ITowarRepository productRepository)
{
repository = productRepository;
}
public ViewResult List()
{
return View(repository.Towar);
}
}
public interface ITowarRepository
{
IQueryable<Towar> Towar { get; }
}
public DbSet<Towar> Towar { get; set; }
public class EFTowarRepository : ITowarRepository
{
public EFDbContext context = new EFDbContext();
public IQueryable<Towar> Towar
{
get { return context.Towar; }
}
}
public class Towar
{
[Key]
public int Id_tow { get; set; }
public string Nazwa { get; set; }
public string Opis { get; set; }
public decimal Cena { get; set; }
public int Id_kat { get; set; }
}
Add the following line to your context:
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
You can tell EF to map to the table Towar by overriding the OnModelCreating method in your DBContext class with fluent API like this:
public class EFDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Towar>().ToTable("Towar");
}
}
Now EF will look for Towar table instead of Towars. If you do not have these tables created, there is some other problem you are having.
EF Code First automatically pluralizes the table names. Use a [Table] attribute to explicitly map the entity to a table name:
[Table("Towary")]
public class Towary
{
// Whatever properties
}
It looks like there's a way to disable pluralization gobally too, see Entity Framework Code First naming conventions - back to plural table names?.
using System.Data.Entity.ModelConfiguration.Conventions;
namespace MVCDemo.Models
{
public class EmployeeContext : DbContext
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
For the sake of completeness #forty-two
I want an object to reference itself. How do I write this model? For eg.
public class Term
{
public int TermId { get; set; }
public string Name { get; set; }
public virtual Term PreviousTerm { get; set; }
public virtual int? PreviousTermId { get; set; }
}
The schema generated is:
TermId
Name
PreviousTermId
PreviousTerm_TermId
So apparently, PreviousTermId serves no purpose here as a relationship FK.
But when using automapper, I have to map to PreviousTermId, I cant create the new object PreviousTerm and assign the Id to that. How do I fix this?
Try specifying the mappings in onModel OnModelCreating event
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Term>().HasOptional(t =>t.PreviousTerm).WithMany().
HasForeignKey(t=>t.PreviousTermId);
}