I created a database, then applied dataase-first. Then it automatically imported the database to VS. Please tell me, when database-first automatically indicates relationship? Probably not, my data is not being imported. Could you tell me how to establish connections correctly? I read about the fluent api and about the fact that you can specify keys and properties directly in the table classes (And when is it better to do through fluent, and when to specify directly?)
My 1st table
namespace WcfRestFullService.Model
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Web;
[DataContract]
public partial class customer
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public customer()
{
this.dishesrankings = new HashSet<dishesranking>();
this.orders = new HashSet<order>();
}
[DataMember]
public int Id_Cus { get; set; }
[DataMember]
public string FirstName_Cus { get; set; }
[DataMember]
public string LastName_Cus { get; set; }
[DataMember]
public int PhoneNum_Cus { get; set; }
[DataMember]
public string Email_Cus { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<dishesranking> dishesrankings { get; set; }
public virtual customerpreference customerpreference { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<order> orders { get; set; }
}
}
My 2nd table
namespace WcfRestFullService.Model
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Runtime.Serialization;
using System.Web;
[DataContract]
public partial class customerpreference
{
[DataMember]
public int Id_Cus { get; set; }
[DataMember]
public int Id_Res { get; set; }
[DataMember]
public string Name_Dis { get; set; }
[DataMember]
public int Id_Type { get; set; }
public virtual customer customer { get; set; }
public virtual order order { get; set; }
public virtual type_dishes type_dishes { get; set; }
}
}
MySQLEntities
namespace WcfRestFullService.Model
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
public partial class MySQLEntities : DbContext
{
public MySQLEntities()
: base("name=MySQLEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<customer>()
.HasMany(c => c.customerpreference)
.WithOptional(o => o.Customer);
//throw new UnintentionalCodeFirstException();//here problem
}
public virtual DbSet<customer> customers { get; set; }
public virtual DbSet<customerpreference> customerpreferences { get; set; }
public virtual DbSet<dish> dishes { get; set; }
public virtual DbSet<dishesranking> dishesrankings { get; set; }
public virtual DbSet<ingridient> ingridients { get; set; }
public virtual DbSet<order> orders { get; set; }
public virtual DbSet<restaraunt> restaraunts { get; set; }
public virtual DbSet<type_dishes> type_dishes { get; set; }
public object Parameters { get; internal set; }
}
}
Here I create data(Id_Cus) but it doesn't import in 2nd table
public void InsertCustomer(customer customerDataContract)
{
//MySQLEntities Cust = new MySQLEntities();
customer cust = new customer();
{
cust.Id_Cus = Convert.ToInt32(customerDataContract.Id_Cus);
cust.FirstName_Cus = customerDataContract.FirstName_Cus;
cust.LastName_Cus = customerDataContract.LastName_Cus;
cust.PhoneNum_Cus = Convert.ToInt32(customerDataContract.PhoneNum_Cus);
cust.Email_Cus = customerDataContract.Email_Cus;
};
dc.customers.Add(cust);
customerpreference custPref = new customerpreference()
{
Id_Cus = customerDataContract.Id_Cus,
Id_Res = 0, // some value
Name_Dis = null, // some value
Id_Type = 0 // some value
};
dc.customerpreferences.Add(custPref);
dc.SaveChanges();
int k = Convert.ToInt32(cust.Id_Cus);
customer custFromDb =(from n in dc.customers
where n.Id_Cus == k
select n).Include(c => c.customerpreference).First();
}
perhaps problem in
cust = (from n in dc.customers
where n.Id_Cus == k
select n).Include(c =>c.customerpreference).ToList().First();
dc.customers.Add(cust);
dc.SaveChanges();
Yes it does automatically model foreign keys. You can see that it has done so in your model because there are navigation properties such as dishesrankings in your Customer class.
We had a database first project. We would update it by changing the database using dbup and then updating the model from the database. This way you ensure consistency between the model and the database.
DbUp: https://dbup.github.io/
DbUp is a tool to run scripts to make changes to the database that allows versioning and rollback and it is very useful if you're using database first.
Related
I have several classes in my real code but for this problem I will focus on the two at hand. I have a List class which contains a Name and Items. There is also a Group class which has a name and Items. The relationship used to be List -> Group (many) -> Items. The default for our data seemed to trend more toward List -> Items (many) -> Group where an item may, or may not, be grouped. To accomplish this I simply removed the ListId and navigational item from the Group class. I am able to load the Items just fine but whenever I try to access the Groups DbSet it gives me the following error:
Invalid column name 'List_ListId'.
Here is the code for the classes and the DbContext. I am using EF6 (not core). I have tried recreating the Group class, restarting Visual Studio, restarting SQL Server, and wiping the publish directory to make sure it is clean. Help?
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
namespace MyProject.Database
{
[Table("dbo.Lists")]
public class List
{
[Key]
public int ListId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public bool SortAsNumeric { get; set; }
public virtual List<ListItem> Items { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
namespace MyProject.Database
{
[Table("dbo.ListGroups")]
public class ListGroup
{
[Key]
public int ListGroupId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public int OrderSequence { get; set; }
[NotMapped]
public List<ListItem> Items { get; set; }
public ListGroup()
{
this.Items = new List<ListItem>();
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
namespace MyProject.Database
{
[Table("dbo.ListItems")]
public class ListItem
{
[Key]
public int ListItemId { get; set; }
[Required]
public string Label { get; set; }
[Required]
public string Value { get; set; }
public string Subtext { get; set; }
public string Icon { get; set; }
public string Thumbnail { get; set; }
public int OrderSequence { get; set; }
[NotMapped]
public bool Selected { get; set; }
public int ListId { get; set; }
public virtual List List { get; set; }
public int? ListGroupId { get; set; }
public virtual ListGroup Group { get; set; }
public virtual List<ListItemProperty> Properties { get; set; }
public ListItem()
{
this.OrderSequence = 1;
this.Selected = false;
this.Properties = new List<ListItemProperty>();
}
}
}
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web.Mvc;
namespace MyProject.Database
{
public class ListContext : DbContext
{
public ListContext() : base("MyConnectionString") {}
public virtual DbSet<List> Lists { get; set; }
public virtual DbSet<ListItem> Items { get; set; }
public virtual DbSet<ListGroup> Groups { get; set; }
public virtual DbSet<ListItemProperty> Properties { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<List>()
.HasMany(l => l.Items)
.WithRequired(li => li.List)
.HasForeignKey<int>(li => li.ListId);
modelBuilder.Entity<ListItem>()
.HasMany(li => li.Properties)
.WithRequired(p => p.Item)
.HasForeignKey<int>(p => p.ListItemId);
}
}
}
NOTE: The following code is working. The problem comes when I attempt to access this.Groups in the context.
List MyList = Lists
.Where(x => x.Name == ListName)
.Include(x => x.Items.Select(i => i.Properties))
.SingleOrDefault();
I am using EF6, I have a 1:N relationship between Owners and Widgets. I can't seem to get the associated Owner information.
public partial class Owners
{
public Owners()
{
Widgets = new HashSet<Widgets>();
}
public int Id { get; set; }
public string OwnerName { get; set; }
public virtual ICollection<Widgets> Widgets { get; set; }
}
public partial class Widgets
{
public int id { get; set; }
public int OwnerId { get; set; }
public string WidgetName { get; set; }
public string WidgetType { get; set; }
public virtual Owners Owners { get; set; }
}
public partial class Model1 : DbContext
{
public Model1(): base("name=Model1"){}
public virtual DbSet<Owners> Owners { get; set; }
public virtual DbSet<Widgets> Widgets { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Owners>()
.HasMany(e => e.Widgets)
.WithRequired(e => e.Owners)
.HasForeignKey(e => e.OwnerId)
.WillCascadeOnDelete(false);
}
}
The problem is when I run following query I only get information for Widgets
and nothing for Owners. If I pull the generated SQL out and run it in the database I get all the Information and Associated Entity Information?
I believe I'm overlooking something simple here.
using (var db = new Model1())
{
var rslt = db.Widgets.Include(y => y.Owners);
var rslt2 = await rslt.Where(s => s.WidgetType == "Garthug").ToListAsync();
return rslt2;
}
This is the EF generated SQL statement that gets created and shows all the correct information that I'm looking for when I run in the Database. (I hand typed it but it should be correct)
SELECT
Widgets.id AS id,
Widgets.OwnerId AS OwnerId,
Widgets.WidgetName AS WidgetName,
Widgets.WidgetsType AS WidgetType,
Owners.Id AS Id1,
Owners.OwnerName AS OwnerName
FROM [dbo].Widgets AS Widgets
INNER JOIN [dbo].Owners AS Owner ON Widgets.OwnerId = Owners.Id
WHERE Widgets.WidgetType = 'Garthug'
It Appears that my setup is Correct for EVERY table except Asp Identity Tables... Does anyone know why?
Widgets.OwnerId is associated with Owner.Id so the types are same
But the sort order and equality aren't necessarily the same between .NET and the database. So you could have a collation conflict between the database and EF, where the Widget.OwnerId's match Owner.Id's in the collation of the database, but not in .NET's string comparison rules.
EG
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ef62test
{
class Program
{
public partial class Owner
{
public string Id { get; set; }
public string OwnerName { get; set; }
public virtual ICollection<Widget> Widgets { get; } = new HashSet<Widget>();
}
public partial class Widget
{
public int id { get; set; }
public string OwnerId { get; set; }
public string WidgetName { get; set; }
public string WidgetType { get; set; }
public virtual Owner Owners { get; set; }
}
public partial class Model1 : DbContext
{
public virtual DbSet<Owner> Owners { get; set; }
public virtual DbSet<Widget> Widgets { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Owner>()
.HasMany(e => e.Widgets)
.WithRequired(e => e.Owners)
.HasForeignKey(e => e.OwnerId)
.WillCascadeOnDelete(false);
}
}
static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseAlways<Model1>());
string ownerId = "owner1";
using (var db = new Model1())
{
db.Database.Log = s => Console.WriteLine(s);
var o = new Owner() { Id = ownerId };
db.Owners.Add(o);
for (int i = 0; i < 10; i++)
{
o.Widgets.Add(new Widget());
}
db.SaveChanges();
ownerId = o.Id;
db.Database.ExecuteSqlCommand("update widgets set ownerId = UPPER(ownerId);");
}
using (var db = new Model1())
{
db.Database.Log = s => Console.WriteLine(s);
db.Configuration.LazyLoadingEnabled = false;
var owner = db.Owners.Include(o => o.Widgets).Where(o => o.Id == ownerId).First();
Console.WriteLine(owner.Widgets.Count());
}
Console.WriteLine("Hit any key to exit.");
Console.ReadKey();
}
}
}
If it is the aspnetusers table, does it exist in the same context as your other table? That would explain why EF was struggling even if the database is not?
I have a probably simple question, I am trying to create many to many relationships using entity framework and fluent api, and my problem is that when i try to do any query or view a object in debug it has always 0 items.
I am using junction table that looks like:
So relations exists, to be sure ive checked:
select candidate.firstname, skillset.name
from candidate
join candidate_skillset on candidate.id = candidate_skillset.candidate_id
join skillset on candidate_skillset.skillset_id = skillset.id
and joined results are displayed.
Now my context looks like:
public class CatalogContexct : DbContext
{
public DbSet<Candidate> Candidates { get; set; }
public DbSet<SkillSet> SkillSets { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Candidate>().HasMany(t => t.SkillSets).WithMany(t => t.Candidates)
.Map(m =>
{
m.ToTable("candidate_skillset");
m.MapLeftKey("candidate_id");
m.MapRightKey("skillset_id");
});
modelBuilder.Entity<SkillSet>().ToTable("skillset");
modelBuilder.Entity<Candidate>().ToTable("candidate");
}
}
My left side model candidates:
[Table("candidate")]
public class Candidate
{
public Candidate()
{
this.SkillSets = new HashSet<SkillSet>();
}
[Key]
public int id { get; set; }
[Column("firstname")]
public string Firstname { get; set; }
public int? commendation_id { get; set; }
[ForeignKey("commendation_id")]
public Commendation commendation { get; set; }
public ICollection<SkillSet> SkillSets { get; set; }
}
And my rightside model skillset:
[Table("skillset")]
public class SkillSet : SimpleDictionary
{
public SkillSet()
{
this.Candidates = new HashSet<Candidate>();
}
public virtual ICollection<Candidate> Candidates { get; set; }
}
and that model has a parent class:
public class SimpleDictionary
{
[Key]
public int id { get; set; }
[Column("name")]
public string Name { get; set; }
}
So all should work but when I do for example:
var ca = this._catalog.Candidates
.Include("SkillSets").Include("commendation").
FirstOrDefault(x => x.SkillSets.Any());
Result is null, also when I view object on debug collection of property skillset allays has 0 elements, any idea what could be wrong with it?
I tried this with same structure mentioned here in you question and tried locally . And I am able to get the data with this code . Please try this and let me know if this helps . I just omitted commendation table for simplicity .
var context = new SampleDbContext();
var candidates = context.Candidates
.Include("SkillSets").ToList();
foreach (var candidate in candidates)
{
foreach (var sk in candidate.SkillSets.Where( s1 => s1.Candidates.Count(c=>c.id == candidate.id)>0 ))
{
Console.WriteLine( string.Format(#" Name : {0} Skill :{1}",candidate.Firstname ,sk.Name ) );
}
}
Below is my DbContext and Other Entity Classes
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
public class SampleDbContext : DbContext
{
public SampleDbContext()
: base("name=SampleDBConnection")
{
this.Configuration.LazyLoadingEnabled = false;
}
public DbSet<Candidate> Candidates { get; set; }
public DbSet<SkillSet> SkillSets { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Candidate>().HasMany(t => t.SkillSets).WithMany(t => t.Candidates)
.Map(m =>
{
m.ToTable("candidate_skillset");
m.MapLeftKey("candidate_id");
m.MapRightKey("skillset_id");
});
modelBuilder.Entity<SkillSet>().ToTable("skillset");
modelBuilder.Entity<Candidate>().ToTable("candidate");
}
}
[Table("candidate")]
public class Candidate
{
public Candidate()
{
this.SkillSets = new HashSet<SkillSet>();
}
[Key]
public int id { get; set; }
[Column("firstname")]
public string Firstname { get; set; }
public int? commendation_id { get; set; }
//[ForeignKey("commendation_id")]
//public Commendation commendation { get; set; }
public ICollection<SkillSet> SkillSets { get; set; }
}
public class SimpleDictionary
{
[Key]
public int id { get; set; }
[Column("name")]
public string Name { get; set; }
}
[Table("skillset")]
public class SkillSet : SimpleDictionary
{
public SkillSet()
{
this.Candidates = new HashSet<Candidate>();
}
public virtual ICollection<Candidate> Candidates { get; set; }
}
}
The output of the query you mentioned and the result of my code both matched I hope this is that you wanted .
I have a annoying problem with my code.
My model :
public class Option
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Conference> Conference { set; get; }
}
public partial class Conference
{
[Key, ForeignKey("User")]
public int UserId { get; set; }
public virtual Option Option { set; get; }
public virtual User User { get; set; }
}
public partial class User
{
public int Id {get; set; }
public string Name { get; set; }
public virtual Conference Conference { get; set; }
}
And now i`m getting Option object from Db by dbSet.Find(id) (RepositoryFactory) and what i want to do is to save newly created User, but with selected Option.
If i do like that:
var option = dbSet.Find(id);
var user = new User()
{
Name = "Name",
Conference = new Conference
{
Option = option
}
};
//...
context.SaveChanges();
I`m getting an exception:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
What I`m doing wrong?
Edit: I Tried to create Mapping, but this doesn`t seems to work too.
modelBuilder.Entity<Conference>()
.HasKey(x => x.UserId)
.HasRequired(x => x.User)
.WithOptional(user => user.Conference);
modelBuilder.Entity<Option>()
.HasMany(option => option.Conferences)
.WithRequired(conference => conference.Option)
.HasForeignKey(conference => conference.UserId);
Are you trying to achieve a 1:1 relationship between User and Conference? If so, you need to add an Id (key) property to User. Please see the comments I added to the code sample below regarding the 1:1 relationship. I would advise further evaluation of your domain layer to ensure this is what you are trying to achieve...
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
namespace Stackoverflow
{
public class EntityContext : DbContext
{
public IDbSet<Conference> Conferences { get; set; }
public IDbSet<Option> Options { get; set; }
public IDbSet<User> Users { get; set; }
}
public class Option
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Conference> Conference { set; get; }
}
public class Conference
{
// In one-to-one relation one end must be principal and second end must be dependent.
// User is the one which will be inserted first and which can exist without the dependent one.
// Conference end is the one which must be inserted after the principal because it has foreign key to the principal.
[Key, ForeignKey("User")]
public int UserId { get; set; }
public int OptionId { get; set; }
public virtual Option Option { set; get; }
public virtual User User { get; set; }
}
public class User
{
// user requires a key
public int Id { get; set; }
public string Name { get; set; }
public virtual Conference Conference { get; set; }
}
class Program
{
static void Main(string[] args)
{
using (var entityContext = new EntityContext())
{
// added to facilitate your example
var newOption = new Option {Name = "SomeOptionName"};
entityContext.Options.Add(newOption);
entityContext.SaveChanges();
var option = entityContext.Options.Find(newOption.Id);
var user = new User
{
Name = "Name",
Conference = new Conference
{
Option = option
}
};
// need to add the user
entityContext.Users.Add(user);
//...
entityContext.SaveChanges();
}
}
}
}
I am learning EF Code First from "Programming Entity Framework Code First". The following code snippets are copied from page 5 to page 7.
Visit.cs
using System;
namespace ChapterOne
{
class Visit
{
public int Id { get; set; }
public DateTime Date { get; set; }
public String ReasonForVisit { get; set; }
public String Outcome { get; set; }
public Decimal Weight { get; set; }
public int PatientId { get; set; }
}
}
AnimalType.cs
namespace ChapterOne
{
class AnimalType
{
public int Id { get; set; }
public string TypeName { get; set; }
}
}
Patient.cs
using System;
using System.Collections.Generic;
namespace ChapterOne
{
class Patient
{
public Patient()
{
Visits = new List<Visit>();
}
public int Id { get; set; }
public string Name { get; set; }
public DateTime BirthDate { get; set; }
public AnimalType AnimalType { get; set; }
public DateTime FirstVisit { get; set; }
public List<Visit> Visits { get; set; }
}
}
VetContext.cs
using System.Data.Entity;
namespace ChapterOne
{
class VetContext : DbContext
{
public DbSet<Patient> Patients { get; set; }
public DbSet<Visit> Visits { get; set; }
}
}
Program.cs
using System;
using System.Collections.Generic;
namespace ChapterOne
{
class Program
{
static void Main(string[] args)
{
var dog = new AnimalType { TypeName = "Dog" };
var patient = new Patient
{
Name = "Simpson",
BirthDate = new DateTime(2008, 1, 28),
AnimalType = dog,
Visits = new List<Visit>
{
new Visit
{
Date = new DateTime(2011, 9, 1)
}
}
};
using (var context = new VetContext())
{
context.Patients.Add(patient);
context.SaveChanges();
}
}
}
}
Unfortunately, I got the following error. Could you tell me what is wrong?
Probably you're not filling all required fields. The one i noticed is Patient.FirstVisit default value is not acceptable by sql server.
Not sure if this is the cause of your exact error, but will probably cause another error too; Your VetContext should contain 1 more line:
public DbSet<AnimalType> AnimalTypes { get; set; }
Otherwise, EF won't make an AnimalType table in the DB to insert the
var dog = new AnimalType { TypeName = "Dog" };
record into.