Entity Frameworks - adding 2 records with a FK:PK relationship - entity-framework

I defined my 2 classes as:
public class User
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Email { get; set; }
public Address Address { get; set; }
}
public class Address
{
public int Id { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
Note that I did not define an AddressId field in User. When EF creates the database for the above fields, it adds the User.AddressId column in the database and declares it an FK. So all good.
But now I want to insert data programmatically. I tried the following:
public class UserManagerDbContext: DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// add an address to database
Address addr = New Address
{
Id = 1,
Street = "John Doe",
City = "Boulder",
State = "CO",
Zip = "12345"
};
modelBuilder.Entity<User>()
.HasData(new User
{
Id = 1,
Name = "John Doe",
Email = "a#b.c",
Address = address
}
);
}
// ...
But that fails with the following exception:
System.InvalidOperationException: 'The seed entity for entity type 'User' cannot be added because no value was provided for the required property 'AddressId'.'
I understand why it's throwing this error - I need to enter both table entries separately and then, on inserting into the user table, include the AddressId value. But how can I do this? There is no AddressId field in the class.

You can try this
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// add an address to database
Address addr = new Address
{
Id = 1,
Street = "John Doe",
City = "Boulder",
State = "CO",
Zip = "12345"
};
modelBuilder.Entity<Address>()
.HasData(addr);
modelBuilder.Entity<User>()
.HasData(new User
{
Id = 1,
Name = "John Doe",
Email = "a#b.c",
AddressId = addr.Id,
}
);
}

Related

Entity Framework add object to related entity without loading

I would like to add an object to a related entity without loading them.
I have Company entity defined like this:
public class Company
{
public int ID { get; set; }
public List<Employee> EmployeeList{ get; set; }
}
And Employee entity like this
public class Employee
{
public int ID { get; set; }
public String Name{ get; set; }
}
I want to add an employee to a list placed in that company object without loading all the employees.
I know I can use this expression
Company myCompany= systemBD.Companies.Include("EmployeeList").Find(1) myCompany.EmployeeList.Add(newEmployee)
but I'm afraid that this would consume a lot of time since I have thousands of employees in my database.
Is there a way to add a new employee to an existing company without loading the list of Employees?
I was looking into the Attach method but it does not seem to work.
using (var systemDB = new CompanyDB())
{
Employee employee = new Employee ();
Company companySearch = systemDB.Companies.Where(d => d.Name.Equals("John")).SingleOrDefault();
if (companySearch != null)
{
if (companySearch.EmployeeList != null)
{
systemDB.Companies.Attach(companySearch );
companySearch.EmployeeList.Add(employee);
systemDB.SaveChanges();
}
}
I tried that code but it doesn't work.
Assuming you have your Company and Employee entities defined to have both a navigation property from a Company to the collection of all of its associated Employees and a property from an Employee to its single associated Company, you can accomplish creating a new Employee and associating it with an existing Company from the Employees DB set.
[Table("Company")]
public partial class Company
{
public Company()
{
this.Employees = new HashSet<Employee>();
}
public int Id { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
public virtual ICollection<Employee> Employees { get; set; }
}
[Table("Employee")]
public partial class Employee
{
public int Id { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
public int CompanyId { get; set; }
public virtual Company Company { get; set; }
}
public partial class Database : DbContext
{
public Database()
: base("name=Database")
{
}
public virtual DbSet<Company> Companies { get; set; }
public virtual DbSet<Employee> Employees { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Company>()
.Property(e => e.Name)
.IsUnicode(false);
modelBuilder.Entity<Company>()
.HasMany(e => e.Employees)
.WithRequired(e => e.Company)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Employee>()
.Property(e => e.Name)
.IsUnicode(false);
}
}
Then assuming you already have a Company in the system with an Id of 1, you can do the following:
using (var database = new Database())
{
var company = database.Companies.Find(1);
if (company != null)
{
var employee = new Employee
{
Name = "John Doe",
Company = company
};
database.Employees.Add(employee);
database.SaveChanges();
}
}
OR...if you are sure that Company Id 1 definitely exists...
using (var database = new Database())
{
var employee = new Employee
{
Name = "John Doe",
CompanyId = 1
};
database.Employees.Add(employee);
database.SaveChanges();
}
I think you would need to change your Database Design to accomplish what you want.
Employee table
ID (Primary key)
Name
Company table
ID (Primary key)
Name
EmployeeCompany table
IDCompany (Foreign Key)
IDEmployee (ForeignKey)
This way you will accomplish what you want

ED Code First One to Many Relationship Issue - ASP Identity

I'm configuring a database for ASP Identity and I've hit a snag.
I'm looking to create a One to Many relationship between two tables, which are ApplicationUser & OrganisationUnit.
An OrganisationUnit can have multiple ApplicationUsers, with an ApplicationUser only belonging to one OrganisationUnit
When I add a migration and update the database I get an error during execution :-
System.Data.SqlClient.SqlException: The INSERT statement conflicted
with the FOREIGN KEY constraint
"FK_dbo.AspNetUsers_dbo.OrganisationUnits_OrganisationUnitRefId". The
conflict occurred in database "DefaultConnection", table
"dbo.OrganisationUnits", column 'OrganisationUnitId'.
Here are the tables I'm trying to create :-
public class ApplicationUser : IdentityUser
{
[Required]
[MaxLength(100)]
public string Forename { get; set; }
[Required]
[MaxLength(100)]
public string Surname { get; set; }
[Required]
public DateTime DateCreated { get; set; }
public Guid OrganisationUnitId { get; set; }
[ForeignKey("OrganisationUnitId")]
public virtual OrganisationUnit OrganisationUnit { get; set; }
}
public class OrganisationUnit
{
public OrganisationUnit()
{
ApplicationUsers = new List<ApplicationUser>();
}
public Guid Id { get; set; }
[Required]
[MaxLength(100)]
public string Name { get; set; }
[Required]
[MaxLength(100)]
public string Telephone { get; set; }
public virtual ICollection<ApplicationUser> ApplicationUsers { get; set; }
}
In my seed method for the Configuration.cs have the following code :-
protected override void Seed(ApplicationDbContext context)
{
// This method will be called after migrating to the latest version.
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var ou = new OrganisationUnit()
{
Id = Guid.NewGuid(),
Name = "Group1",
Telephone = "1234567890",
};
var user = new ApplicationUser()
{
UserName = "SuperPowerUser",
Email = "derek#rdsadfasdf.com",
EmailConfirmed = true,
Forename = "Derek",
Surname = "Rivers",
DateCreated = DateTime.Now.AddYears(-3),
OrganisationUnitId = ou.Id
};
userManager.Create(user, "MySuperP#ssword!");
}
}
you should try :
var user = new ApplicationUser()
{
UserName = "SuperPowerUser",
Email = "derek#rdsadfasdf.com",
EmailConfirmed = true,
Forename = "Derek",
Surname = "Rivers",
DateCreated = DateTime.Now.AddYears(-3),
OrganisationUnit = ou
};
With your syntax (only provinding a FK) you assume that the Organisation exists.

DBContext not updating foreign key on update

We are migrating over from EF4 to EF5 and part of this is the move from POCO Generator created classes to the DBContext generated classes. However, we are now seeing issues where the foreign keys are not being set on updates.
I have the following
public abstract partial class Contact
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Nullable<int> AddressID { get; set; }
public virtual Address Address { get; set; }
}
public partial class UserContact : Contact
{
public string Description { get; set; }
public string Notes { get; set; }
}
public partial class Address
{
public string Line1 { get; set; }
public string Line2 { get; set; }
}
If I create a contact without an address, in my first operation, then update the contact to add an address in the next operation, the AddressID in the contact is not being populated - it remains null. So, when I do this:
UserContact contact = new UserContact
{
FirstName = "fname",
LastName = "lname"
};
int contactID = _contactAccessor.AddContact(contact); // add contact no address
UserContact retContact = m_contactAccessor.GetContact(contactID);
retContact.Address = new Address
{
Line1 = "line1",
Line2 = "line2",
};
m_contactAccessor.UpdateContact(retrievedContact); // add an address to the contact
In the ContactAccessor, my UpdateContact method does this:
public void UpdateContact(UserContact userContact)
{
UserContact retrievedContact = (from c in context.Contact.OfType<UserContact>()
.Include(c => c.Address)
where (c.ID == userContact.ID)
select c).FirstOrDefault());
retrievedContact.Address = userContact.Address;
context.Entry<Contact>(retrievedContact).CurrentValues.SetValues(userContact);
context.SaveChanges());
}
If I look at the database, the contact is created, as is the new address, but the AddressID on the contact is null, so the contact has no association with the address.
I'm not sure what I am doing wrong.

EF 5.0 not removing optional one to one navigation property

Setting an optional one to one navigation property to null in Entity Framework 5 does not seem to make it to the database. Is this expected behavior?
In the example below, Person is a proxy object. I would expect setting the address to null will cause the address to be removed from the database.
The code below works if I lazy load the address before setting it null. But loading the address before
Any help will be greatly appreciated.
namespace ConsoleApplication2
{
using System;
using System.Data.Entity;
internal class Program
{
private static void Main(string[] args)
{
using (PersonContext context = new PersonContext())
{
// Make sure person with Id = 1 exists with an address.
Person person = context.People.Find(1) ?? context.People.Add(new Person { Id = 1 });
if (person.Address == null)
{
person.Address = new Address
{
Street = "123 Main Street",
City = "SomeCity",
State = new State
{
Code = "NY",
Name = "New York"
},
Zip = "11771"
};
}
context.SaveChanges();
}
// Setting address to null should remove relationship
using (PersonContext context = new PersonContext())
{
Person person = context.People.Find(1);
Console.WriteLine("Person is a " + person.GetType());
person.Address = null;
context.SaveChanges();
if (person.Address == null)
{
Console.WriteLine("Success: Person.Address is null.");
}
else
{
Console.WriteLine("Failure: Person.Address is not null.");
}
}
}
}
public class Person
{
public int Id { get; set; }
public virtual Address Address { get; set; }
}
public class Address
{
public int Person_Id { get; set; }
public string Street { get; set; }
public string City { get; set; }
public int StateId { get; set; }
public State State { get; set; }
public string Zip { get; set; }
}
public class State
{
public int Id { get; set; }
public string Code { get; set; }
public string Name { get; set; }
}
public class PersonContext : DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<State> States { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Address>()
.HasKey(x => x.Person_Id);
modelBuilder.Entity<Person>()
.HasOptional<Address>(x => x.Address)
.WithRequired()
.WillCascadeOnDelete();
}
}
}
Where you are not using lazy loading, the related properties such as Address will not be loaded and so will already be null.
To ensure it is always loaded use eager loading :
Person person = context.People.Include(x => x.Address).Single(x => x.Id == 1);

Entity Framework - Adding parent is also trying to add child when I don't want it to

I have two objects (WishListItem and Product) in a one-to-many relationship. WishListItem has to have a product. Each Product can be in 0 - n WishListItems.
public class WishListItem
{
public int Id { get; set; }
public int ProductId { get; set; }
public Product Product { get; set; }
}
public class Product
{
public int Id { get; set; }
// ... other properties
}
The Product has no knowledge of WishListItems. All of the Products exist. I just want to add a new WishListItem. My WishListItem model for the relationship is this:
HasRequired(p => p.Product).WithMany().HasForeignKey(p => p.ProductId);
When I try to add a new item like this:
WishListItem item = new WishListItem();
// ... sets properties
WishListItems.Add(item); // WishListItems is of type DbSet<WishListItem>
SaveChanges();
This code seems to try to also add a Product. I don't want to add a new Product (or even update it). The Product property is set to null. How do I tell Entity Framework that I only want to add the WishListItem? Do I need to Ignore the Product property (by doing Ignore(p => p.Product); in my WishListItem model) and load the Product separately whenever I load my WishListItem objects?
I have solved my issue. The problem came from another property on the Product object.
private bool _isFreeShippingInitialValue;
public bool IsFreeShipping
{
get
{
return _isFreeShippingInitialValue ||
computedValueFromAnotherChildObject;
}
set
{
_isFreeShippingInitialValue = value;
}
}
We noticed that when you first get the Product object, the IsFreeShipping.get is called (not sure why) before any child objects are loaded. For example, if _isFreeShippingInitialValue is false and computedValueFromAnotherChildObject is true, IsFreeShipping first returns false (because computedValueFromAnotherChildObject is first false since no child objects have been loaded), then true the next time you try to get IsFreeShipping. This makes EF think the value has changed.
The first item we added to WishListItems worked fine. It was the second item that broke. We believe SaveChanges() (or something prior to it) loaded the Product for the first WishListItem. The SaveChanges() was breaking on the Product of the first WishListItem when we were adding the second item.
So, in short, be careful when computing values in a Property.get using child objects because it can bite you in the butt.
This works for me without adding any new Addresses records. In this model, Person has an optional home address, but address doesn't have any knowledge of the person.
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual Address HomeAddress { get; set; }
public int HomeAddress_id { get; set; }
}
public class Address
{
public int Id { get; set; }
public string PhoneNumber { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
}
In the DbContext override, I have the below code
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasRequired(t => t.HomeAddress).WithMany()
.HasForeignKey(t => t.HomeAddress_id);
}
I can write a unit test like this.
var addressId = 0;
using (var db = new DataContext())
{
var address = new Address { City = "test", Country = "test", PhoneNumber = "test", State = "test", Street = "test" };
db.Addresses.Add(address);
db.SaveChanges();
addressId = address.Id;
}
using (var db = new DataContext())
{
var person = new Person { Email = "test#test.com", FirstName = "Testy", LastName = "Tester", HomeAddress_id = addressId };
db.Persons.Add(person);
db.SaveChanges();
}