EF inserting object to DB getting validation error - c#

I am trying insert into database my model with relation one to many:
I have two models:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public virtual Country Country { get; set; }
}
public class Country
{
public int Id { get; set; }
public string CountryName { get; set; }
public virtual ICollection<User> Users { get; set; }
}
User user = new User()
{
Name = model.Name,
Surname = model.Surname,
Country = new Country { Id = 1 }
};
When I try to insert it to the database I get exception
Validation failed for one or more entities.
The CountryName field is required (CoutryName column is required in database)
I don't want each time call to database to get full Country object, any ideas?

Instead of instancing a new country, do something like this:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public int CountryId { get; set; }
[ForeignKey("CountryId")]
public virtual Country Country { get; set; }
}
public class Country
{
public int Id { get; set; }
public string CountryName { get; set; }
public virtual ICollection<User> Users { get; set; }
}
User user = new User()
{
Name = model.Name,
Surname = model.Surname,
CountryId = 1;
};
This explicitly sets the CountryID on the User.

You should use "FK Associations" instead "Independent Associations" this is create article about it:
http://blogs.msdn.com/b/efdesign/archive/2009/03/16/foreign-keys-in-the-entity-framework.aspx

Related

Entity Framework : When child entity is added, a duplicate parent entity is created instead of referencing existing entity?

A product can have multiple reviews. A review is made by a single customer.
Therefore, review has both Customer and Product as properties.
Product.cs
namespace DatabaseProject.Models
{
public class Product
{
public Product()
{
Reviews = new List < Review >();
}
public int Id { get; set; }
public Catagory Catagory { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Specification { get; set; }
public List<Review> Reviews { get; set; }
}
}
Review.cs
namespace DatabaseProject.Models
{
public class Review
{
public int Id { get; set; }
public string Text { get; set; }
public int Stars { get; set; }
[Required]
public Product Product { get; set; }
[Required]
public Customer Customer { get; set; }
}
}
Customer.cs
namespace DatabaseProject.Models
{
public class Customer
{
public Customer()
{
Addresses = new List<Address>();
Reviews = new List<Review>();
}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public List<Address> Addresses { get; set; }
public List<Review> Reviews { get; set; }
}
}
Method to add new review.
I add it to the reviews list in product table.
public bool AddReview(int id, Review review)
{
using (var context = new ShopDbContext())
{
Product oldProduct = context.Products.Find(id);
if (oldProduct == null)
{
return false;
}
oldProduct.Reviews.Add(review);
context.SaveChanges();
return true;
}
}
Adding a new Review
Here, since the review is added to product.Reviews I didn't have to pass the product property.
But I had to pass the customer. Somehow this creates a new customer rather than referencing the existing customer.
productService.AddReview(1,
new Review
{
Customer = customerService.Get(1),
Stars = 2,
Text = "It's a good camera",
});
This causes a duplicate entry in Customers table.
I think you need a CustomerId propery in your Reviews table, and pass the customerId when adding a new review.
public class Review
{
public int Id { get; set; }
public string Text { get; set; }
public int Stars { get; set; }
[Required]
public int ProductId { get; set; }
[Required]
public int CustomerId { get; set; }
[ForeignKey("ProductId")]
public Product Product { get; set; }
[ForeignKey("CustomerId")]
public Customer Customer { get; set; }
}
productService.AddReview(1,
new Review
{
CustomerId = 1,
ProductId = XXX,
Stars = 2,
Text = "It's a good camera",
})
Then, you would need to create a foreign key between ProductId and Product table, and CustomerId and Customer table.
In this way, you wouldn't need to load the customer/product when addign a new review. You will only need the identifiers.
Your Review Model should have a CustomerID & Review Model should look like this:
namespace DatabaseProject.Models
{
public class Review
{
public int Id { get; set; }
[Required]
public int CustomerId { get; set; }
[Required]
public int ProductId { get; set; }
public string Text { get; set; }
public int Stars { get; set; }
[ForeignKey("ProductId")]
public Product Product { get; set; }
[ForeignKey("CustomerId")]
public Customer Customer { get; set; }
}
}
And you must add a new review like this:
productService.AddReview(1,
new Review
{
CustomerId = 1,
Stars = 2,
Text = "It's a good camera",
ProductId = 1
})
In present code you are passing an object of Customer Model in DbSet.Add method which adds a new entity to a context

Create a new list with fields of 2 entities

I have 2 entities being them: Employees and SendMessage:
public class Employee
{
[DbColumn(IsIdentity =true, IsPrimary =true)]
public long EmployeeId { get; set; }
[DbColumn]
public string Name { get; set; }
[DbColumn]
public string Surname { get; set; }
[DbColumn]
public string Date_Birth { get; set; }
[DbColumn]
public string Home_Address { get; set; }
[DbColumn]
public string City { get; set; }
[DbColumn]
public string Postcode { get; set; }
[DbColumn]
public string Telephone { get; set; }
[DbColumn]
public string Mobile { get; set; }
[DbColumn]
public string Email { get; set; }
[DbColumn]
public long ShiftId { get; set; }
}
As you can see the EmployeeId field is to connect the two
public class MessageSent
{
[DbColumn(IsIdentity =true, IsPrimary =true)]
public long MessageSentId { get; set; }
[DbColumn]
public long EmployeeId { get; set; }
[DbColumn]
public long MessageSentSeq { get; set; }
[DbColumn]
public string Status { get; set; }
[DbColumn]
public string DateSent { get; set; }
}
To redeem I use the following method
gvEmployee.DataSource = new EmployeeService().GetAll();
Now comes my need I need to show on my new screen the following fields:
MessageSentId,EmployeeId,MessageSentSeq of the table MessageSent and Name,Surname of the table Employees.
How can I create a third list with these 5 fields to fill my grid?
Take your employees:
var employees = new EmployeeService().GetAll();
Then your messages:
var messages = new MessageSentService().GetAll(); // probably like this, idk what its in your code
Using the LINQ query syntax is much clearer, more natural, and makes it easier to spot errors:
var query =
from employee in employees
join message in messages
on employee.EmployeeId equals message.EmployeeId
select new {
MessageSentId = message.MessageId,
EmployeeId = message.EmployeeId,
MessageSentSeq = message.MessageSentSeq,
Name = employee.Name,
Surname = employee.Surname
};
Then you can use query and its fields.

Owned type mapping EF Core fails when saving

I want to make TableSplitting using Owned Types. I have the following model:
public class Account
{
public GUID Id { get; set; }
public string Email { get; set; }
public StreetAddress Address { get; set; }
}
public class StreetAddress
{
public string Name { get; set; }
public string Address { get; set; }
public string Zipcode { get; set; }
public string City { get; set; }
public string Country { get; set; }
public Location Location { get; set; }
}
public class Location
{
public double Lat { get; set; }
public double Lng { get; set; }
}
And I defined my mapping of the Account like this:
public override void Map(EntityTypeBuilder<Account> map)
{
// Keys
map.HasKey(x => x.Id);
// Indexs
map.HasIndex(x => x.Email).IsUnique();
// Property mappings.
map.Property(x => x.Email).HasMaxLength(255).IsRequired();
// Owned types.
map.OwnsOne(x => x.Address, cb => cb.OwnsOne(a => a.Location));
}
When I run the migration things are working and the columns are created in the database. But when I try to insert and save an address like so:
var account1 = new Account("e#mail.com", "First", "Last")
{
Address = new StreetAddress()
{
Address1 = "Street 1",
City = "City",
Zipcode = "2000",
Country = "Denmark",
Location = new Location()
{
Lat = 0.0,
Lng = 5.5
}
}
};
this.Context.Accounts.Add(account1);
I get this error
Message "The entity of 'Account' is sharing the table 'Accounts' with
'Account.Address#StreetAddress', but there is no entity of this type
with the same key value 'Id:b7662057-44c2-4f3f-2cf0-08d504db1849' that
has been marked as 'Added'."
Consider using virtual properties. This can also be used for lazy loading in your application
public class Account
{
public GUID Id { get; set; }
public string Email { get; set; }
public virtual StreetAddress Address { get; set; }
}
public class StreetAddress
{
public string Name { get; set; }
public string Address { get; set; }
public string Zipcode { get; set; }
public string City { get; set; }
public string Country { get; set; }
public virtual Location Location { get; set; }
}
public class Location
{
public double Lat { get; set; }
public double Lng { get; set; }
}
You must add constructors and initialize owned entities.
public class Account
{
public Account (){
Address = new StreetAddress();
}
public GUID Id { get; set; }
public string Email { get; set; }
public StreetAddress Address { get; set; }
}
public class StreetAddress
{
public StreetAddress(){
Location = new Location();
}
public string Name { get; set; }
public string Address { get; set; }
public string Zipcode { get; set; }
public string City { get; set; }
public string Country { get; set; }
public Location Location { get; set; }
}
public class Location
{
public double Lat { get; set; }
public double Lng { get; set; }
}
In other words there can't be optional owned entities.
Note: if you have a non-empty constructor you also must add empty constructor due to ef core limitations.
public class Account {
public GUID Id { get; set; }
public string Email { get; set; }
public StreetAddress Address { get; set; }
}
public class StreetAddress {
public string Name { get; set; }
public string Address { get; set; }
public string Zipcode { get; set; }
public string City { get; set; }
public string Country { get; set; }
public Location[] Location { get; set; }
public class Location {
public double Lat { get; set; }
public double Lng { get; set; }
}
try this because once you call your object in the shape of all is in relation with Account class but the reality is you don't define that relation which I made
For an Account to be added in the database. It's references should be saved first in the table. For adding data in database it should be in the following order: Location > StreetAddress > Account
I am sure if you try adding every object to the context then build the parent it would work
meaning add the location first and then create address and reference the location object u made
add the address to the context
afterwards create and account and reference the added address in it!
Or you could add ctors to ur models that init new instances of each navigation property
one last thing, this really shouldn't be an issue as of EF Core 5 since it has tons of new bells and whistles when it comes to navigation properties
public override void Map(EntityTypeBuilder<Account> map)
{
// Keys
map.HasKey(x => x.Id);
// Indexs
map.HasIndex(x => x.Email).IsUnique();
// Property mappings.
map.Property(x => x.Email).HasMaxLength(255).IsRequired();
// Owned types.
map.OwnsOne(x => x.Address, cb => cb.OwnsOne(a => a.Location));
}
if you're using it, you really dont need the following part
just add your DbSet<T>s appropriately and thats it

Foreign key value not populating automatically

I've created a foreign key reference to the 'ApplicationUser' entity in my 'YogaSpace' entity seen below, but when I create a new YogaSpace and save it to the DB the column 'ApplicationUserRefId' is null? Shouldn't it contain the user id from application user without me inserting it into the entity before I save it? I know the answer would seem to be yes because I have another member in 'YogaSpace' called Images and it gets the 'YogaSpace' entity id automatically without me inserting it into the 'Images' entity before I save. So I don't have to insert the id there. How come it doesn't insert the user id with 'YogaSpace'?
public class YogaSpace
{
public int YogaSpaceId { get; set; }
public virtual ICollection<YogaSpaceImage> Images { get; set; }
[MaxLength(128)]
public string ApplicationUserRefId { get; set; }
[ForeignKey("ApplicationUserRefId")]
public virtual ApplicationUser ApplicationUser { get; set; }
}
public class ApplicationUser : IdentityUser
{
public DateTime MembershipCreated { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime? Birthdate { get; set; }
public Gender Gender { get; set; }
public virtual ICollection<YogaSpace> YogaSpaces { get; set; }
}
public class YogaSpaceImage
{
public int YogaSpaceImageId { get; set; }
public byte[] Image { get; set; }
public byte[] ImageThumbnail { get; set; }
public string ContentType { get; set; }
public int Ordering { get; set; }
[Index]
public int YogaSpaceRefId { get; set; }
[ForeignKey("YogaSpaceRefId")]
public virtual YogaSpace YogaSpace { get; set; }
}
Here is how I create a 'YogaSpace' entity. You can see I don't put anything into 'ApplicationUserRefId', BUT I expect it to autopopulate with user id from Application User, just like YogaSpacerefId gets auto populated when I create an image and save it.
var newSpace = new YogaSpace
{
Overview = new YogaSpaceOverview
{
Title = viewModel.Title,
Completed = ListingComplete.Incomplete
},
Listing = new YogaSpaceListing
{
Accommodation = (YogaSpaceAccommodation)viewModel.YogaSpaceAccommodation,
SpaceLocation = (YogaSpaceLocation)viewModel.YogaSpaceLocation,
SpaceType = (YogaSpaceType)viewModel.YogaSpaceType
},
Details = new YogaSpaceDetails
{
Completed = ListingComplete.Complete
},
Address = new YogaSpaceAddress
{
Completed = ListingComplete.Incomplete
},
DateCreated = DateTime.Now
};
yogaSpaceRepository.InsertOrUpdate(newSpace);
yogaSpaceRepository.Save();

Entity Framework many to many to single object

I am trying to map a property on a user that that has a many to many relationship in the database but there is only ever one per user. But I am unable to figure out the required map in entityframework. I have the following entities:
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
//Need to map this property
public virtual SecurityRole SecurityRole { get; set; }
}
public class SecurityRole
{
public int Id { get; set; }
public string Name { get; set; }
}
An the following tables:
User:
Id
FirstName
LastName
SecurityRole:
Id
Name
UserSecurityRole:
UserId
SecurityRoleId
If anyone has any idea or could point me in the right direction that would be great
Even if there is only one record in the database, if you have a many to many relationship between User and SecurityRole it should work like this:
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public List<SecurityRole> SecurityRoles { get; set; }
}
public class SecurityRole
{
public int Id { get; set; }
public string Name { get; set; }
public List<User> Users { get; set; }
}

Categories