Error Seeding Database, foreign key issue - entity-framework

I have built out my models using POCO. When I go to seed my database I get:
Unable to determine the principal end of the 'CSP.Models.Type_Color' relationship. Multiple added entities may have the same primary key
Here's the models in question:
public class Type
{
[Key]
[ScaffoldColumn(false)]
public int TypeId { get; set; }
[Required(ErrorMessage = "A Type Name is Required")]
[Display(Name="Type")]
public string Name { get; set; }
public int ColorId { get; set; }
public bool Other { get; set; }
//Navigations
[ForeignKey("ColorId")]
public virtual Color Color { get; set; }
public virtual List<Tools> tools { get; set; }
}
public class Color
{
[Key]
[ScaffoldColumn(false)]
public int ColorId { get; set; }
[Required(ErrorMessage = "A name is required")]
public string Name { get; set; }
public string Description { get; set; }
//navigation
public virtual List<Type> Types { get; set; }
}
Most of the markup I did after reading suggestions.
My seed code that is getting the error is here:
var colors = new List<Color>
{
new Color{Name="Red"},
new Color{Name="White"}
};
var types = new List<Type>
{
new Type{ Name="Hammer", Color = colors.Where(ws => ws.Name=="Red").Single()},
new Type{ Name= "Electric", Color = colors.Where(ws => ws.Name=="Red").Single()}
};
new List<Tool>
{
new Wine{ Maker= Maker.Single(v => v.Name=="HammerCo"), Type= types.Single(wt => wt.Name=="hammer")},
}
}.ForEach(a => context.Tools.Add(a));
context.SaveChanges();
I also tried adding each value to the context and then saving. I got this error after it tried saving the type entity:
[System.Data.SqlClient.SqlException] = {"The INSERT statement conflicted with the FOREIGN KEY constraint \"Type_Color\". The conflict occurred in database \"TestTools\", table \"dbo.Colors\", column 'ColorId'.\r\nThe statement has been terminated."}
What am I missing?

What is happening is your objects all have the default int value (0) for their primary key. When you add them to the context, EF detects this and throws an error (two objects of the same type cannot have the same key, in this case, 0. I assume your primary key fields in the database are set as IDENTITY columns and will auto increment +1 on insert. This may sound odd, but you need to give your objects placeholder IDs which will be replaced on insert with the IDENTITY values.
new Color{ColorId = 1, Name="Red"},
new Color{ColorId = 2, Name="White"}
new Type{TypeId = 1, Name="Hammer", ...}
new Type(TypeId = 2, Name="Electric", ...}

Related

Drop foreign key for UserClaim or change model Code first approach

I created a linked table between Users and Tenants called UserTenants.
Now I want to drop the foreign key column: UserId. The problem is that I can't find the model for UserClaim which I can edit. I've tried to create a new one like this:
public class UserClaim : CreationAuditedEntity<long>{
[Key]
public int Id { get; set; }
public const int MaxClaimTypeLength = 256;
public virtual int? TenantId { get; set; }
public virtual long UserId { get; set; }
public virtual User User { get; set; }
[StringLength(256)]
public virtual string ClaimType { get; set; }
public virtual string ClaimValue { get; set; }
public UserClaim() {
}
public UserClaim(AbpUserBase user, Claim claim)
{
TenantId = user.TenantId;
UserId = user.Id;
ClaimType = claim.Type;
ClaimValue = claim.Value;
}
}
But the Error I'm getting is:
System.InvalidOperationException: Cannot use table 'UserClaims' for entity type 'UserClaim' since it is being used for entity type 'UserClaim' and potentially other entity types, but there is no linking relationship. Add a foreign key to 'UserClaim' on the primary key properties and pointing to the primary key on another entity type mapped to 'UserClaims'.

How to Allow NULL Foreign Keys with SQLite-net-extensions

I'm trying to add a nullable foreign key mapping but it doesn't work. I know the database allows nulls, since I can insert a new record with a null foreign key when using Datagrip. I only get the error when trying to insert from a Xamarin.Forms project building for Android(SQLite.SQLiteException: 'Constraint')
My classes look like:
public class Item
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
...
[ForeignKey(typeof(Location))]
public int LocationId { get; set; }
[ManyToOne]
public Location Location { get; set; }
}
public class Location
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
...
[OneToMany]
public List<Item> Items { get; set; }
}
And my inserts like
//This will no work
var todoItem = new Item()
{
Name = "Test item " + DateTime.Now.TimeOfDay.ToString(),
Description = "Desc",
Location = null // I tried with and without this line
};
await App.Database.SaveItemAsync(todoItem);
//This will work
var todoItem = new Item()
{
Name = "Test item " + DateTime.Now.TimeOfDay.ToString(),
Description = "Desc",
LocationId = 1
};
await App.Database.SaveItemAsync(todoItem);
Any idea what I'm doing wrong? Thanks
Apparently the library needs that the id field to be nullable, so instead of
[ForeignKey(typeof(Location))]
public int LocationId { get; set; }
I should use
[ForeignKey(typeof(Location))]
public int? LocationId { get; set; }
PS: In my case just building the project didn't took the changes on to effect, I only could see the result after Rebuild the project..(I'm new with Xamarin, probably I have something misconfigured...I hope)

Entity Framework Invalid column name Height_HeightID

I am trying to get records from the Height Table based on foreign key relationships with parent table. But I am getting Invalid Column Name.... Error. Here is my model setup:-
[Table("Candidate")]
public partial class Candidate
{
public Candidate()
{
Heights = new HashSet<Height>();
Weights = new HashSet<Weight>();
}
[Key]
public int CandidateID { get; set; }
[StringLength(64)]
public string FirstName { get; set; }
[StringLength(64)]
public string LastName{ get; set; }
}
Then I have a Height and Weight Table. Model of Height table is:-
[Table("Height")]
public partial class Height
{
[Key]
public int HeightID { get; set; }
public int? CandidateID { get; set; }
public double? HeightVal { get; set; }
ForeignKey("CandidateID")]
public virtual Candidate Candidate { get; set; }
}
And here is LinQ query:-
return (from c in _db.Candidates
join h in _db.Heights
on c.CandidateID equals h.CandidateID
where c.CandidateID == candidateId
select t);
When i try to get records using these models, I am getting this error:-
System.Data.SqlClient.SqlException: Invalid column name
'Height_HeightID
As suggested by similar stackoverflow, I have added ForeignKey[] DataAnnotation but I am still getting same error.
Also in my Sql Server Database, Height Table has foreign key constraint on CandidateID.

Many to Many relationships with look up tables

public class Person {
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[ManyToMany(typeof(PersonColor), CascadeOperations = CascadeOperation.All)]
public List<Color> FavoriteColors { get; set; }
}
public class Color {
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
[ManyToMany(typeof(PersonColor))]
public List<Person> People { get; set; }
}
public class PersonColor {
[ForeignKey(typeof(Person))]
public int PersonId { get; set; }
[ForeignKey(typeof(Color))]
public int ColorId { get; set; }
}
...
var person = new Person() {
FirstName = "Adrian",
LastName = "Simbulan",
FavoriteColors = new List<Color>() {
new Color() {Name = "Red"},
new Color() {Name = "Green"}
}
};
await _db.InsertWithChildrenAsync(person);
Ok so i'm trying to establish a many to many relationship between Person and Color. The color table will be pre-populated with static data.
Now the problem is, whenever I execute the "InsertWithChildrenAsync" command, it always inserts new data into the Color lookup table. Is there a way to insert a Person record with selected colors with out affecting the Color table?
Try removing the write cascade operation from FavoriteColors attribute:
[ManyToMany(typeof(PersonColor), CascadeOperations = CascadeOperation.CascadeRead)]
public List<Color> FavoriteColors { get; set; }
This way the library won't perform recursive write operations on that table.
Another way without modifying the relationship is performing a two-step operation. First inserting the object and then updating the relationship:
await _db.InsertAsync(person);
await _db.UpdateWithChildrenAsync(person);
In both cases the the objects in the FavoriteColors list should already exist in the database and should have a valid primary key assigned. According to this, your sample code will never work because the identifier is 0 in all Color objects.

Retrieving the value in an association table in Entity Framework code first

I am using EF 4.1 code first and I am struggling with the association entity and getting the value that was set in the association table. I tried to follow the post on: Create code first, many to many, with additional fields in association table.
My tables are as follows (all are in plural form):
Table: Products
Id int
Name varchar(50)
Table: Specifications
Id int
Name varchar(50)
Table: ProductSpecifications
ProductId int
SpecificationId int
SpecificationValue varchar(50)
My related classes:
public class Product : IEntity
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ProductSpecification> ProductSpecifications { get; set; }
}
public class Specification : IEntity
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ProductSpecification> ProductSpecifications { get; set; }
}
public class ProductSpecification
{
public int ProductId { get; set; }
public virtual Product Product { get; set; }
public int SpecificationId { get; set; }
public virtual Specification Specification { get; set; }
public string SpecificationValue { get; set; }
}
My context class:
public class MyContext : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<Specification> Specifications { get; set; }
public DbSet<ProductSpecification> ProductSpecifications { get; set; }
protected override void OnModelCreating(DbModelBuilder dbModelBuilder)
{
}
}
My repository method where I do my call (not sure if it is correct):
public class ProductRepository : IProductRepository
{
MyContext db = new MyContext();
public Product GetById(int id)
{
var product = db.Products
.Where(x => x.Id == id)
.Select(p => new
{
Product = p,
Specifications = p.ProductSpecifications.Select(s => s.Specification)
})
.SingleOrDefault();
return null; // It returns null because I don't know how to return a Product object?
}
}
Here is the error that I am getting back:
One or more validation errors were detected during model generation:
System.Data.Edm.EdmEntityType: : EntityType 'ProductSpecification' has no key defined. Define the key for this EntityType.
System.Data.Edm.EdmEntitySet: EntityType: EntitySet �ProductSpecifications� is based on type �ProductSpecification� that has no keys defined.
What does it mean that no keys are defined? Won't the ProductId and SpecificationId map to Id of Product and Id of Specification respectively?
How would I return a single product with the all the specifications for it?
Entity Framework will recognize that ProductId is a foreign key property for the Product navigation property and SpecificationId is a foreign key property for the Specification navigation property. But the exception complains about a missing primary key ("Key" = "Primary Key") on your ProductSpecification entity. Every entity needs a key property defined. This can happen either by conventions - by a specific naming of the key property - or explicity with data annotations or Fluent API.
Your ProductSpecification class doesn't have a property which EF would recognize as a key by convention: No Id property and no ProductSpecificationId (class name + "Id").
So you must define it explicitely. Defining it with data annotations is shown in the post you linked:
public class ProductSpecification
{
[Key, Column(Order = 0)]
public int ProductId { get; set; }
public virtual Product Product { get; set; }
[Key, Column(Order = 1)]
public int SpecificationId { get; set; }
public virtual Specification Specification { get; set; }
public string SpecificationValue { get; set; }
}
And in Fluent API it would be:
modelBuilder.Entity<ProductSpecification>()
.HasKey(ps => new { ps.ProductId, ps.SpecificationId });
Both ways define a composite key and each of the parts is a foreign key to the Product or Specification table at the same time. (You don't need to define the FK properties explicitely because EF recognizes it due to their convention-friendly names.)
You can return a product including all specifications with eager loading for example:
var product = db.Products
.Include(p => p.ProductSpecifications.Select(ps => ps.Specification))
.SingleOrDefault(x => x.Id == id);