Suppose you have
public class A
{
public string _myString;
}
And this context:
public class MyContext: DbContext
{
public DbSet<A> myASet{ get; set; }
}
Now, is there a way to tell EF to generate an identity column for myASet?
I don't want to add an ID field to class A, so I wonder if EF could do this.
Many thanks,
Juergen
You must add ID column to your class if you want to have it in the database. Also in EF each entity must have mapped primary key.
EF will only use columns which are actually in your model classes, so you have to put all the ones you want in yourself. This includes identity columns for primary keys.
If you have an entity called Product and a property called 'ProductId' , EF will automatically add the identity column as it looks for entity name + Id by convention.
You can use a column that does not comply with the convention by adding a [key] attribute above the desired property.
In the example below. An identity column will be created for ProductId.
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public string CategoryId { get; set; }
public virtual Category Category { get; set; }
}
In this example, the column 'MyId' will be created as an identity.
public class Product
{
[key]
public int MyId { get; set; }
public string Name { get; set; }
public string CategoryId { get; set; }
public virtual Category Category { get; set; }
}
Related
I have these two classes:
public class Item
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public Store Location { get; set; }
}
public class Store
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
I want to seed some example data in my ASP.NET Core Entity Framework Core WebAPI Code First application.
So I saw I can use something like:
modelBuilder.Entity<Item>().HasData(new Item {<properties>});
Two problems:
If I don't provide a value for "ID" I get an exception that it is required.
If I provide a value for Location like new Store{<etc.>} I get an error that no value was provided for LocationID which is the column in my database in table "Items" that is a foreign key linking that table with table "Stores".
How do I seed a new "Item" in my database when that class doesn't have a "LocationID" property? And must I first specifically add a "Store" before adding an "Item"? I was hoping there would be some sort of automatic cascade insert.
About your questions:
You just provide Id since you are seeding initial data
You have to insert Stores, there is no such thing as "cascade insert", what would EF insert as Name in automatically generated Stores?
So you need also to seed your Stores like you are seeding Items:
modelBuilder.Entity<Store>().HasData(new Store {<properties>});
What would I also do, is to change you models like this:
public class Item
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int StoreId { get; set; } //or LocationId if you prefer
[Required]
public Store Location { get; set; }
}
public class Store
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<Item> Items { get; set; }
}
and you need to set this as foreign key for your Location object:
modelBuilder.Entity<Item>().HasOne(e => e.Location)
.WithMany(e => e.Items)
.HasForeignKey(e => e.StoreId)
.OnDelete(DeleteBehavior.Restrict);
after that you can just adjust your seed method to:
modelBuilder.Entity<Item>().HasData(new Item { Id = 1, StoreId = 1 });
Note that there is no need to instantiate Location object.
I am using Entity Framework's automatic migrations with a code-first approach.
I dont use the packet manager console and dont have access to coded migrations.
I have a line representing my table in my model here :
public virtual DbSet<Customer> Customers { get; set; }
I renamed one of the fields of Customer :
[Table("Customers")]
public partial class Customer
{
[Key]
[Column(TypeName = "numeric")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int idCustomer { get; set; }
public string name { get; set; }
public int age { get; set; }
public string mail { get; set; }
public string password { get; set; }
}
I just changed "mail" to "mailModified".
But when the database got updated, Entity deleted all data from the name field.
I think it deleted my column to create a new one with the new name.
How to avoid that ? How to make him understand to only rename the column ?
Thanks for any participation
You have to do it using Migration commands.. so that data won't be lost ..
Else u can add the following code to auto-generated up and down method
RenameColumn("dbo.MyTable", "NewColumn", "OldColumn");
Try using Column Attribute when you create your table class
class Table
{
[Column("ColumnName")]
public int Column1 { get; set; }
[Column("ColumnName")]
public int Column2 { get; set; }
}
When using data annotations with EF4.1 RC is there an annotation to cause cascade deletes?
public class Category
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public ICollection<Product> Products { get; set; }
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public Category Category { get; set; }
}
Using this model the constraint generated is:
ALTER TABLE [Product] ADD CONSTRAINT [Product_Category]
FOREIGN KEY ([Category_Id]) REFERENCES [Categorys]([Id])
ON DELETE NO ACTION ON UPDATE NO ACTION;
If not how is it achieved?
Putting required on the Product table Category relationship field solves this
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
[Required] //<======= Forces Cascade delete
public Category Category { get; set; }
}
I like to turn off cascade delete by default (by removing the OneToManyCascadeDeleteConvention)
I was then hoping to add them back in via annotations, but was surprised that EF doesn't include a CascadeDeleteAttribute.
After spending way too long working around EF's ridiculous internal accessor levels, the code in this gist adds a convention that allows attributes to be used: https://gist.github.com/tystol/20b07bd4e0043d43faff
To use, just stick the [CascadeDelete] on either end of the navigation properties for the relationship, and add the convention in your DbContext's OnModeCreating callback. eg:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
modelBuilder.Conventions.Add<CascadeDeleteAttributeConvention>();
}
And in your model:
public class BlogPost
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
[CascadeDelete]
public List<BlogPostComment> Comments { get; set; }
}
Not sure on Data Annotations, but you can add it in the database by modifying the actual relationship.
Looks like the answer is no for data annotations:
http://social.msdn.microsoft.com/Forums/en-US/adonetefx/thread/394821ae-ab28-4b3f-b554-184a6d1ba72d/
This question appears to show how to do it with the fluent syntax, but not sure if that applies for 4.1 RC
EF 4.1 RC: Weird Cascade Delete
As an additional example to Tyson's answer, I use the [CascadeDelete] attribute like follows in an entity, which successfully adds the "Cascade" delete rule to the Parent-Child relation.
public class Child
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
[SkipTracking]
public Guid Id { get; set; }
[CascadeDelete]
public virtual Parent Parent { get; set; }
[Required]
[ForeignKey("Parent")]
public Guid ParentId { get; set; }
}
I have created these entities Product, Order, OrderedItem in EF using Code First.
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
[NotMapped]
public int IssuedQuantity { get; set; }
[NotMapped]
public int InhandQuantity { get; set; }
public virtual ICollection<OrderedItem> OrderedItems { get; set; }
...
}
public class Order
{
public int Id { get; set; }
public string ReferenceNumber { get; set; }
public virtual ICollection<OrderedItem> OrderedItems { get; set; }
...
}
public class OrderedItem
{
public int OrderId { get; set; }
public string ProductId { get; set; }
[ForeignKey("OrderId")]
public virtual Order Order { get; set; }
[ForeignKey("ProductId")]
public virtual Product Product { get; set; }
...
}
Now I want to get all products by passing current user id to a stored procedure. It will then return all products along with total product quantity currently in user's hand.
The problem is that EF is not mapping SP results back to Product entity for NotMapped properties. i.e. all properties in product entity have values but NotMapped properties are set to NULL even when I return their values from SP.
What I want to ask is that does EF support this kind of functionality? If yes then how?
NOTE I know about Computed Properties but that will create unneccessary columns in tables and I don't want that, since these properties are calculated at run-time.
NOTE I know that I don't need to create OrderedItem entity. But I am storing some other properties in it, which are removed here for brevity.
I'm quite sure that EF does not support dynamic mapping (you could try to change the mapping metadata but is not a clean way or delete the mapping cache but then EF will be very slow). In this case the razionale is that the entity are 2 different entities because they have different data. In your case probably the best thing is to do 2 entities the ProductWithQuantities that inherits from Product.
BTW Thinking about ERPs, the model of orders/wms usually is different. Products does not contain informations about QtyOnHand or sales/buy information. Usually is another object (Inventory?) that contains this informations.
I would create a View Model of the product with all the required properties and pass that to the view instead of the Product model. Then you are not constrained by the mappings of the Product model and you do not have to use the [NotMapped] Attribute on the fields.
[NotMapped]
public class ProductVM
{
public int Id { get; set; }
public string Name { get; set; }
public int IssuedQuantity { get; set; }
public int InhandQuantity { get; set; }
public virtual ICollection<OrderedItem> OrderedItems { get; set; }
...
}
I hope that helps.
I have seen many examples of implementing a one to one relationship, but I failed doing mine, because the requirements are some kind different (Guid with database generated option, foreign key property and so on).
I have 2 classes (Bundesland, Programmkonfiguration) that have a 1:1 relationship (both ends are required in business sense) but cannot be joined into one table
Requirements to Bundesland:
Guid Id as Key but without a DatabaseGenerated Attribute
Navigation Property Programmkonfiguration
Bundesland.cs:
public class Bundesland
{
[Key]
public Guid Id { get; set; }
public virtual Programmkonfiguration Programmkonfiguration { get; set; }
}
Requirements to Bundesland
Guid Id as Key generated from Database
ForeignKey Property Bundesland_Id (needed with _ for interface)
Navigation Property Bundesland
Programmkonfiguration.cs:
public class Programmkonfiguration
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public Guid Bundesland_Id { get; set; }
public virtual Bundesland Bundesland { get; set; }
}
database schema should look like this
table Bundesland (Id)
table Programmkonfiguration (Id, Bundesland_Id)
Why I failed until now:
EF doesn’t recognize the relationship by itself
if I use either attributes (ForeignKey, Required) or fluent API and the mode builder is not failing, the foreign key property Programmkonfiguration.Bundesland_Id is never set, after context.SaveChanges()
If you want to help me, here are additional classes you may gonna need: https://gist.github.com/anonymous/9cb554cd864e3dbee1ac
I am using .NET 4.5(.1) with EF5, but I failed with EF6 too
Thanks in advance :)
You can use fluent configuration for this:
public class Bundesland
{
[Key]
[ForeignKey("Programmkonfiguration")]
public Guid Id { get; set; }
public virtual Programmkonfiguration Programmkonfiguration { get; set; }
}
public class BundesLandConfiguration: EntityTypeConfiguration<Bundesland>
{
public BundesLandConfiguration()
{
HasProperty(p=>p.Id)
HasRequired(p=>p.Programmkonfiguration).WithRequiredPrincipal(p=>p.Bundesland);
}
}
public class Programmkonfiguration
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public Guid Bundesland_Id { get; set; }
public virtual Bundesland Bundesland { get; set; }
}
public class ProgrammkonfigurationConfiguration: EntityTypeConfiguration<Programmkonfiguration>
{
public ProgrammkonfigurationConfiguration()
{
HasKey(p=>p.Id);
HasProperty(p=>p.Id)
HasProperty(p=>p.Bundesland_Id)
}
}
Do not forget to add this configurations to EntityModelConfigurations in db context.
Update: because property naming is against convention, you should add [ForeignKey] attribute as I added to property Id of Bundesland class.