existing SQL Server Tables
Two Tests :
Call this one A:
[Test]
public void AssertAccessPolicyWithIdAndChecksum()
{
var pol = Repo.GetPolicyFlightStatus(aut_id: 44544, checksum: "QXSDENY");
Assert.NotNull(pol);
}
call this one B
[Test]
public void AssertGetFriendlyPolicy()
{
var lineRepo = new tbl_StatusRepository();
var pol = Repo.GetPolicyFlightStatus(aut_id: 44544, checksum: "QXSDENY");
Assert.AreEqual("With Underwriter", pol.tbl_Status.txt_friendlyName);
Assert.AreEqual("WC/Longshore", pol.tbl_Line.txt_friendlyName);
}
Models :
public partial class tbl_Policy
{
[Key]
public int aut_id { get; set; }
[ForeignKey("tbl_Status")]
public int int_statusID { get; set; }
public virtual tbl_Status tbl_Status { get; set; }
[ForeignKey("tbl_Line")]
public int int_lineID { get; set; }
public virtual tbl_Line tbl_Line { get; set; }
}
public class tbl_Status
{
[Key]
public int aut_id { get; set; }
public string txt_status { get; set; }
public string txt_friendlyName { get; set; }
public virtual tbl_Policy tbl_Policy { get; set; }
}
public class tbl_Line
{
[Key]
public int aut_id { get; set; }
public string txt_Line { get; set; }
public string txt_friendlyName { get; set; }
public virtual tbl_Policy tbl_Policy { get; set; }
}
When Running
internal static tbl_Policy GetPolicyFlightStatus(int aut_id, string checksum)
{
if (Transcoder.Transcode(aut_id) == checksum)
{
var ctx = new LIGDataContext();
return ctx.tbl_Policy.Include("tbl_Line").Include("tbl_Status").Single(f => f.aut_id == aut_id);
}
return null;
}
TestA passes
TestB throws Exception on first Assert Line
Adding Includes For SubTables
internal static tbl_Policy GetPolicyFlightStatus(int aut_id, string checksum)
{
if (Transcoder.Transcode(aut_id) == checksum)
{
var ctx = new LIGDataContext();
return ctx.tbl_Policy.Include("tbl_Line").Include("tbl_Status").Single(f => f.aut_id == aut_id);
}
return null;
}
Test A and Test B Throw
LIG2010RedesignMVC3.LIGMVC2010FlightTrackerTests.AssertAccessPolicyWithIdAndChecksum:
System.InvalidOperationException : Sequence contains no elements
LIG2010RedesignMVC3.LIGMVC2010FlightTrackerTests.AssertGetFriendlyPolicy:
System.InvalidOperationException : Sequence contains no elements
There are some problems in your object model. Basically, you are trying to set up a 1:1 association with foreign keys while code first does not really support this scenario. As a result it turns all of your associations to Shared Primary Key Associations and none of the foreign keys on tbl_Policy become a foreign key in the database. First, you need to fix your model since that could cause a bunch of exceptions at runtime.
Currently, there ar two ways to map a 1:1 association in Code-First:
1. Shared Primary Key Associations
2. One-to-One Foreign Key Associations
See which one better describes your domain model and I can change your object model to match that.
I also had to rework my modeling (credit to Morteza but I wanted it here for my records
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<tbl_Line>()
.HasMany(d => d.tbl_Policy)
.WithRequired(c => c.tbl_Line)
.HasForeignKey(c => c.int_lineID);
modelBuilder.Entity<tbl_Status>()
.HasMany(d => d.tbl_Policy)
.WithRequired(c => c.tbl_Status)
.HasForeignKey(c => c.int_statusID);
}
Related
How can I relate the tables below by fluent api?
I need to get the second table data via LinkTable which stores ids of Main and Second tables.
Here are my models:
public class MainTable
{
public int ID { get; set; }
...
...
public ICollection<LinkTable> LinkTable { get; set; }
}
public class LinkTable
{
public int ID { get; set; }
...
...
public MainTable MainTable { get; set; }
public SecondTable SecondTable { get; set; }
}
public class SecondTable
{
public int ID { get; set; }
...
...
public ICollection<LinkTable> LinkTable { get; set; }
}
I mapped like this:
HasRequired(t => t.MainTable).WithMany(t => t.LinkTable).HasForeignKey(t => t.MainTable_ID);
HasRequired(t => t.SecondTable).WithMany(t => t.LinkTable).HasForeignKey(t => t.SecondTable_ID);
And trying to get data :
MyDBContext.MainTable.Include("LinkTable").FirstOrDefault();
When I was trying foreach the LinkTable to get SecondTable data I got an error:
Object reference not set...
#foreach (var item in Model.LinkTable)
{
<p>#item.SecondTable.ID</p>
}
To avoid that exception, you need to initialize your navigation property in a constructor:
public class MainTable
{
public MainTable()
{
LinkTable=new List<LinkTable>();
}
public int ID { get; set; }
...
...
public ICollection<LinkTable> LinkTable { get; set; }
}
Also, you could use Include extension method which is strongly typed and could avoid you possible run-time exceptions:
MyDBContext.MainTable.Include(mt=>mt.LinkTable).FirstOrDefault();
Now if you want to load another level, in this case SecondTable, you can do this:
MyDBContext.MainTable.Include(mt=>mt.LinkTable.Select(lt=>lt.SecontTable)).FirstOrDefault();
In the link I quoted above you can find more examples about how to load different levels.
how do I insert data in many to many relationship?
I have these two models definded by this code
public class Article
{
public int ArticleID { get; set; }
public string Title { get; set; }
public DateTime Date { get; set; }
public string Anotation { get; set; }
public string Body { get; set; }
public virtual ICollection<ArticleTag> ArticleTags { get; set; }
}
public class ArticleTag
{
public int ArticleTagID { get; set; }
public string TagName { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
Now the big Q is how to seed the database with test data. I have some experience with normal tables and queries and in MVC EF I am quite a novice. Normally I would create an association table and in it define the link between these models. But I have read many tutorials and none gave me a deterministic way how to do it, so I you can imagine my confusion.
As I said before, I "created" an assoc table via ModelBuilder and that's where I end :(
public class DatabaseContext : DbContext
{
public DbSet<Article> Articles { get; set; }
public DbSet<ArticleTag> ArticleTags { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Article>().
HasMany(at => at.ArticleTags).WithMany(a => a.Articles).
Map(m => m.MapLeftKey("ArticleID").MapRightKey("ArticleTagID").ToTable("Articles_To_ArticleTags"));
}
}
I need to know the easiest way to seed my DB (don't care if have to delete the assoc table) and understand how it works in the MVC - linking the two models, linking two specific instances, ... , and how to code it all.
Thx for any answer.
So finally solved!
Found a good post here and with this one together I made it work.
In short what I had to do:
Remove my builder link - EF itself creates link (own assoc table)
A little modify models
Create DatabaseInitializer
In the Global.asax to the method Application_Start() add Database.SetInitializer(new DatabaseInitializer()); declaration
don't forget to se ConnectionString and DBcontext
Normally use in a View
Modifications in constructor (not sure if absolutely necessary, maybe it does the same thing as native/default constructor):
public class Article
{
public int ArticleID { get; set; }
public string Title { get; set; }
public DateTime Date { get; set; }
public string Anotation { get; set; }
public string Body { get; set; }
public string SourceLink { get; set; }
public virtual List<ArticleTag> ArticleTags { get; set; }
public Article()
{
ArticleTags = new List<ArticleTag>();
}
}
public class ArticleTag
{
public int ArticleTagID { get; set; }
public string TagName { get; set; }
public virtual List<Article> Articles { get; set; }
public ArticleTag()
{
Articles = new List<Article>();
}
}
And the DatabaseInitializer
public class DatabaseInitializer : DropCreateDatabaseIfModelChanges<DatabaseContext>
{
protected override void Seed(DatabaseContext context)
{
ArticleTag tag1= new ArticleTag { TagName = "aaaa" };
ArticleTag tag2= new ArticleTag { TagName = "bbbb" };
ArticleTag tag3= new ArticleTag { TagName = "cccc" };
var articleTags = new List<ArticleTag> { tag1, tag2, tag3};
articleTags.ForEach(i => context.ArticleTags.Add(i));
context.SaveChanges();
Article a1 = new Article
{
Title = "Title1",
Date = DateTime.Now,
Anotation = "Anotation1",
Body = "article_1",
ArticleTags = new List<ArticleTag> { tag1 }
};
Article a2 = new Article
{
Title = "Title12",
Date = DateTime.Now,
Anotation = "Anotation2",
Body = "article_2",
ArticleTags = new List<ArticleTag> { tag2, tag3 }
};
var articles = new List<Article> { a1, a2 };
articles.ForEach(a => context.Articles.Add(a));
context.SaveChanges();
}
}
I'm using ASP.NET MVC4 EF CodeFirst.
Need help to write LINQ (to entities) code in Index action to get collection of Courses which are attended by selected student. The relationship is many to many with join table with payload.
//StudentController
//-----------------------
public ActionResult Index(int? id)
{
var viewModel = new StudentIndexViewModel();
viewModel.Students = db.Students;
if (id != null)
{
ViewBag.StudentId = id.Value;
// *************PROBLEM IN LINE DOWN. HOW TO MAKE COURSES COLLECTION?
viewModel.Courses = db.Courses
.Include(i => i.StudentsToCourses.Where(t => t.ObjStudent.FkStudentId == id.Value));
}
return View(viewModel);
}
The error I got is:
The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.
I have modeles (the third one is for join table with payload):
//MODEL CLASSES
//-------------
public class Student
{
public int StudentId { get; set; }
public string Name { get; set; }
public virtual ICollection<StudentToCourse> StudentsToCourses { get; set; }
}
public class Course
{
public int CourseId { get; set; }
public string Title { get; set; }
public virtual ICollection<StudentToCourse> StudentsToCourses { get; set; }
}
public class StudentToCourse
{
public int StudentToCourseId { get; set; }
public int FkStudentId { get; set; }
public int FkCourseId { get; set; }
public string Classroom { get; set; }
public virtual Student ObjStudent { get; set; }
public virtual Course ObjCourse { get; set; }
}
Then, here is modelview I need to pass to view
//VIEWMODEL CLASS
//---------------
public class StudentIndexViewModel
{
public IEnumerable<Student> Students { get; set; }
public IEnumerable<Course> Courses { get; set; }
public IEnumerable<StudentToCourse> StudentsToCourses { get; set; }
}
EF does not support conditional include's. You'll need to include all or nothing (ie no Whereinside the Include)
If you need to get the data for just certain relations, you can select it into an anonymous type, something like (the obviously untested);
var intermediary = (from course in db.Courses
from stc in course.StudentsToCourses
where stc.ObjStudent.FkStudentId == id.Value
select new {item, stc}).AsEnumerable();
Obviously, this will require some code changes, since it's no longer a straight forward Course with a StudentsToCourses collection.
I have set up 3 models, code first and the relationships seem to be working but one is causing me a problem.
I have Article, Language and Edition Classes
public class Article
{
public int ID { get; set; }
public string Name { get; set; }
public string Icon { get; set; }
}
public class Language
{
public int ID { get; set; }
public string Name { get; set; }
public string Code { get; set; }
}
public class Edition
{
public int ID { get; set; }
public Article Article { get; set; }
public Language Language { get; set; }
public string Title { get; set; }
public string Details { get; set; }
}
In my bootstrap/DBinitialiser, I can create Objects and populate them fine. The DB is created and the foreign keys for Language and Article are both present on the Edition table and correctly entered.
var engLang = new Language() {Code="en", Name="English Language"};
var altLang = new Language() {Code="xx", Name="Alternative Language"};
db.Languages.Add(engLang);
db.Languages.Add(altLang);
db.SaveChanges();
var testArt = new Article() { Name = "test" };
db.Articles.Add(testArt);
db.SaveChanges();
db.Editions.Add(new Edition(){Article = testArt, Language = engLang, Title="English Content"});
db.Editions.Add(new Edition(){Article = testArt, Language = altLang, Title="Alternative Content"});
db.SaveChanges();
I can now query the Editions and return a list of them, but the Language attribute is always NULL. The Article Attribute works fine.
var query = db.Editions.Where(r => r.Article.ID == Article.ID);
foreach (Edition item in query)
{
// item.Language => NULL
// item.Article => {Object Article}
}
I'm new to .net and Entity-Framework and can't work out why I always get this error.
I can even query by r => r.Language.ID == 1 and still get a NULL attribute on the Edition object.
Make sure you are using EF codefirst in right manner. Here you have some ambiguities. You must determine what relationships actually should exist, in your POCOs. Change classes like bellow:
public class Article
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public string Icon { get; set; }
}
public class Language
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public string Code { get; set; }
}
public class Edition
{
[Key]
public int ID { get; set; }
public virtual Article Article { get; set; }
public virtual Language Language { get; set; }
public string Title { get; set; }
public string Details { get; set; }
}
With thanks to AmirHossein Mehrvarzi for helping me write my models more clearly, I believe this error to be caused by the lazy loading of entities while iterating through the result of the query. ref: Entity Framework: There is already an open DataReader associated with this Command.
Without enabling MultipleActiveResultSets I simply added an Include statement to my linq
var query = db.Editions.Where(r => r.Article.ID == Article.ID).Include(r => r.Language);
foreach (Edition item in query)
{
// item.Language => {Object Language}
// item.Article => {Object Article}
}
I'm traying to do a mapping with One to One relationship with id as "foreign", I can't change the database
Those are the tables
Cutomer
int CustomerId
string Name
CustomerDetail
int CustomerId
string Details
Entity Splittitng does not works for me since i need a left outter join.
Any Ideas?
Thanks in advance,
and sorry about my english.
You can use the Shared Primary Key mapping here.
public class Customer
{
public int CustomerId { get; set; }
public string Name { get; set; }
public virtual CustomerDetail CustomerDetail { get; set; }
}
public class CustomerDetail
{
public int CustomerId { get; set; }
public string Details { get; set; }
public virtual Customer Customer { get; set; }
}
public class MyContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<CustomerDetail>().HasKey(d => d.CustomerId);
modelBuilder.Entity<Customer>().HasOptional(c => c.CustomerDetail)
.WithRequired(d => d.Customer);
}
}