ef code first increase id by 1 - entity-framework

Im using EF to update my database.
This is my model:
//Resource
public long ResourceId { get; set; }
public string Name { get; set; }
public string Descritption { get; set; }
public string UserId { get; set; }
public int ResourceTypeId { get; set; }
public byte[] Data { get; set; }
public bool IsEnabled { get; set; }
public bool Approved { get; set; }
public System.DateTime DateCreated { get; set; }
public virtual ICollection<MetaData> MetaDatas { get; set; }
//MetaData
public long MetaDataId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string LanguageCode { get; set; }
public string UserId { get; set; }
public System.DateTime DateCreated { get; set; }
public virtual ICollection<ResourceMetaList> ResourceMetaLists { get; set; }
public virtual ICollection<Resource> Resources { get; set; }
What is it that makes metadataid increase by 1 everytime i add a new metadata?
I want to be able to add metadata with a specific id?
There is a connectiontabl between resource and metadata where the id of each of them connnects them. so i want to be able to add a specific metadata for each resource but for now it gives it a new id everytime so it is not realy the same metadata that connects to each resource but a new one every time.
Edit
Maybe the problem is not how i modeled my database but how i update the database with data?
There is a connection table between Resource and MetaData and is that table i want to update rather then the metadata table itself. But the connectiontable doesn't have a model class for it self but i exists in the database. How do i update that table only?
EDIT 2
The 3 arrow point to rows that looks the same, they should all be the same row but be connected to a different resource in the table to the left.

you need to switch of the default identity mapping
Ef Fluent API mappings
or use the annotation
[DatabaseGenerated(DatabaseGenerationOption.None)]
int id {get;set;}
EF annotations

You can define and use many-to-many relationships in EF, it doesn't matter if you use a model, or Code First.
There is plenty of information on this if you google "EF many to many relationships".
If you use this EF relationship, you can let EF generate the IDs, and it will do the relationship fix-up for you, and manage the relationship table automatically.

To add / remove relationship you can use ChangeRelationshipState.
For example if you want to add relationship between Metadata 10, 12, 19 And Resource 3.
You can do like this.
using (var db = new AppContext())
{
var r3 = new Resource { ResourceId = 3 };
var m10 = new Metadata { MetadataId = 10 };
var m12 = new Metadata { MetadataId = 12 };
var m19 = new Metadata { MetadataId = 19 };
db.Entry(r3).State = EntityState.Unchanged;
db.Entry(m10).State = EntityState.Unchanged;
db.Entry(m12).State = EntityState.Unchanged;
db.Entry(m19).State = EntityState.Unchanged;
var manager = ((IObjectContextAdapter)db).ObjectContext.ObjectStateManager;
manager.ChangeRelationshipState(r3, m10, h => h.Metadatas, EntityState.Added);
manager.ChangeRelationshipState(r3, m12, h => h.Metadatas, EntityState.Added);
manager.ChangeRelationshipState(r3, m19, h => h.Metadatas, EntityState.Added);
db.SaveChanges();
}

add Key Attribute
[Key]
public long MetaDataId { get; set; }

Related

Entity Framework one to many : SqlException

I have a little problem when I try to save an item in my DB using EntityFramework.
My classes looks like:
public partial class Site
{
public int Id { get; set; }
public string Name { get; set; }
public string LongName { get; set; }
public string Adress { get; set; }
public City City { get; set; }
public Country Country { get; set; }
public string VATNumber { get; set; }
}
public class Country
{
public int CountryId { get; set; }
public string Name { get; set; }
public string IsoCode { get; set; }
}
And when I try to create a new site in my controller it works, but when I try to add a link to an existing Country :
if (SiteProvider.GetSiteByName(Site.Name) == null)
{
Site.Country = CountryProvider.GetCountryById(1);//it's working, i see the link to the right country
SiteProvider.Create(Site);
}
public static void Create(Site Site)
{
using (MyDBContext Context = new MyDBContext())
{
Context.Site.Add(Site);
Context.SaveChanges(); //here is the problem
}
}
I got this error:
SqlException: Cannot insert explicit value for identity column in
table 'Country' when IDENTITY_INSERT is set to OFF
Thanks in advance for your help.
Add CountryId property to Site class and when adding a new Site set CountryId instead of Country property
public int CountryId { get; set; }
[ForeignKey("CountryId")]
public Country Country{ get; set; }
You have a slight issue with your use of contexts here. You have used one DBContext instance to load the country (where this country object will be tracked) and then a second DBContext to save the site (where the first country object is a property).
It is preferable to perform all your operations for a single unit of work by using one DB context (that would be shared between your classes) and the responsibility for disposing of it to be handled outside your repository layer.

If Exists Dont Add Data Entity Framework Many-To-Many

I have these two Models the logic is here One Post can have multiple Categories.
public class Post
{
public Post()
{
this.Categories = new HashSet<Category>();
}
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string ShortDescription { get; set; }
public string PostImage { get; set; }
public string Thumbnail { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime? PublishedDate { get; set; }
public string CreatedBy { get; set; }
public virtual ICollection<Category> Categories { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
I have three static categories.
When I am trying to add new post its multiplexing CategoryTable creating new categories with same name ,And Mapping Them in to CategoryPostsTable.
The problem is here i want to map that data with existing categories. I dont want to add new category with same name.
I am using Repository Pattern how should i control that ? Is EF has some solution for that ?
I assume you have code like:
var post = new Post();
post.Categories.Add(cat);
context.Posts.Add(post);
...where cat is a Category object representing an existing category.
The latter Add method (DbSet.Add) doesn't only mark the received entity as Added but all entities in its object graph that are not attached to the context. So cat will also be marked as Added if it wasn't attached yet.
What you can do is
context.Entry(cat).State = System.Data.Entity.EntityState.Unchanged;
Now EF will only create the association to the category, but not insert a new category.

How to add entity with one to one association in Entity Framework Code first approach?

I am using EF 4.4 + Code First.
I was trying to add a ChartofAccount entity to DBContext with the Company's key filled, but it ask me to fill the Company's CompanyName as well at validation. I thought DBContext will look up the associate Company for me, instead of trying to add a new Company?
public class ChartofAccount: MasterData
{
public ChartofAccount()
{
Company = new Company();
Category1 = new AccountCatagory();
Category2 = new AccountCatagory();
}
[Key]
[Required]
public string Code { get; set; }
public virtual Company Company { get; set; }
[Required]
public string AccountName { get; set; }
[Required]
[StringLength(3)]
public string AccountCurrency { get; set; }
public virtual AccountCatagory Category1 { get; set; }
public virtual AccountCatagory Category2 { get; set; }
public string Reference { get; set; }
public bool HasTransaction { get; set; }
}
public class Company : MasterData
{
[Key]
public int Id { get; set; }
[Required]
public string CompanyName { get; set; }
[Required]
DateTime CurrentAccountPeriod { get; set; }
[Required]
[StringLength(3)]
public string BaseCurrencyCode { get; set; }
}
Sadly, just the primary key of a related entity isn't enough. You need to round trip to the database to obtain the entity in the same data context.
Example:
var Company = db.Company.Single(d => d.ID == id);
ChartofAccountToAdd.Company = Company;
db.ChartofAccount.Add(ChartofAccountToAdd);
db.SubmitChanges();
That will create the relationship with an already existing company.
EDIT:
I completely forgot about this when I answered. Edit your ChartOfAccount model to contain the foreign key for the Company like:
public class ChartofAccount: MasterData
{
{rest of your model}
public int CompanyID { get; set; }
}
and then set the foreign key to that new int property. Entity Framework will create the relationship without any issues. Don't set anything to the Company property on the model.

Getting the record id of a model just saved to the database MVC4 ASP.Net

Using ASP.Net/C# with MVC4 and EF 5. I have a base model in which several other models are linked to via the id. For example
public class Person
{
public int Id { get; set; }
public DateTime? Created { get; set; }
public DateTime? Submitted { get; set; }
public DateTime? Finalized { get; set; }
public string UserProfileSite { get; set; }
public int UserId { get; set; }
public virtual ICollection<Demographic> Demographics { get; set; }
public virtual ICollection<Demographic> Demographics { get; set; }
}
The Demographics have a foreign key with the personId. When they add a person they get sent to fill out the demographics information. However since the demographics have a foriegn key of personId I need to create the person record.
I can create the person before going to the demographics view as follows:
Person person = new Person();
person.UserId = curuser.UserId;
person.UserProfileSite = curuser.Site;
person.Created = DateTime.Now;
db.Persons.Add(person);
db.SaveChanges();
How do I get the personId of the record I just saved to the database so I can pass it to my Demographics so the model has the foreign key of personId?
Assuming you have not turned of changeTracking within entity framework, you should be able to simply get the id of the object after you save it to the database
Person person = new Person();
person.UserId = curuser.UserId;
person.UserProfileSite = curuser.Site;
person.Created = DateTime.Now;
db.Persons.Add(person);
db.SaveChanges();
var personId = person.Id;

Entity Framework 4 CTP 5 POCO - Many-to-many configuration, insertion, and update?

I really need someone to help me to fully understand how to do many-to-many relationship with Entity Framework 4 CTP 5, POCO. I need to understand 3 concepts:
How to config my model to indicates
some tables are many-to-many.
How to properly do insert.
How to properly do update.
Here are my current models:
public class MusicSheet
{
[Key]
public int ID { get; set; }
public string Title { get; set; }
public string Key { get; set; }
public virtual ICollection<Author> Authors { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
public class Author
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public string Bio { get; set; }
public virtual ICollection<MusicSheet> MusicSheets { get; set; }
}
public class Tag
{
[Key]
public int ID { get; set; }
public string TagName { get; set; }
public virtual ICollection<MusicSheet> MusicSheets { get; set; }
}
As you can see, the MusicSheet can have many Authors or Tags, and an Author or Tag can have multiple MusicSheets.
Again, my questions are:
What to do on the
EntityTypeConfiguration to set the
relationship between them as well as
mapping to an table/object that
associates with the many-to-many
relationship.
How to insert a new music sheets
(where it might have multiple
authors or multiple tags).
How to update a music sheet. For
example, I might set TagA,
TagB to MusicSheet1, but later I need to change the tags to TagA
and TagC. It seems like I need
to first check to see if the tags
already exists, if not, insert the
new tag and then associate it with
the music sheet (so that I doesn't
re-insert TagA?). Or this is
something already handled by the
framework?
Thank you very much. I really hope to fully understand it rather than just doing it without fully understand what's going on. Especially on #3.
In the EF4 CTP5 the relationship is done by default convention when you put public virtual ICollection in each of the classes of the many to many relationship, as you already have done, your context class should look like this:
public class YourContextName : DbContext
{
public DbSet<MusicSheet> MusicSheets { get; set; }
public DbSet<Tag> Tags { get; set; }
public DbSet<Author> Authors { get; set; }
}
Very simple you just create a instance of the MusicSheet class and then add all the instances of you authors and tags to each of the collections of Authors and Tags in your MusicSheet, and then add your instance of MusicSheet to your context collection of MusicSheets and then call SaveChanges:
MusicSheet musicSheet = new MusicSheet
{
Title = "Music Sheet 1",
Key = "Key",
Authors = new List<Author>
{
new Author
{
Name = "Author 1",
Bio = "Author 1 biographic text..."
},
new Author
{
Name = "Author 2",
Bio = "Author 2 biographic text..."
}
},
Tags = new List<Tag>
{
new Tag {TagName = "TagA"},
new Tag {TagName = "TagC"}
}
};
var context = new YourContextName();
context.MusicSheets.Add(musicSheet);
context.SaveChanges();
To update you have to load your MusicSheet and remove the tags you don't want and then add the ones you need to add, this is how:
var context = new YourContextName();
var myMusicSheet = context.MusicSheets.First();
//The Tag you wnat to remove.
var tagToRemove = myMusicSheet.Tags.First();
var tagToAdd = new Tag {TagName = "TagX"};
myMusicSheet.Tags.Remove(tagToRemove);
myMusicSheet.Tags.Add(tagToAdd);
context.Entry(myMusicSheet).State = EntityState.Modified;
context.SaveChanges();
You can also find any author and/or tag that you know that exist and added to your MusicSheet and vice versa, but this is the foundation.
Remember this is for the EF4 CTP5 Code first...
Excuse me my English is not my main language, I hope this can help you, best regards from Dominican Republic.
PS: Don't forget to add references to EntityFramework and System.Data.Entity, is your responsibility to do anything else like unit test, validation, exception handling...etc
EDIT:
First you need to add a constructor to your models:
public class Tag
{
[Key]
public int ID { get; set; }
public string TagName { get; set; }
public Tag()
{
MusicSheets = new List<MusicSheet>();
}
public virtual ICollection<MusicSheet> MusicSheets { get; set; }
}
...Then you can do something like this:
var context = new YourContextName();
var newMusicSheet = new MusicSheet();
newMusicSheet.Title = "Newly added Music Sheet";
//Your existing Tag.
var existingTag = contex.Tags.Find(3);
existingTag.MusicSheets.Add(existingTag);
context.Entry(existingTag).State = EntityState.Modified;
context.SaveChanges();
You can do the same for all your models.
I hope this can help you!
You do not really need an EntityTypeConfiguration to set the relationship between them. It should work as it is right now. With CTP5 all you have to do to establish a many-to-many relationship is to include ICollection in both entities.
Now about how to perform inserts and deletes, there are two ways I know of. The one I usually use is create an entity for the resultant table of the many-to-many relationship, then create an instance of this entity and feed it with all the data that is required, including instances of the other entities (the ones that have the many-to-many relationship). And finally I simply add it to the repository and commit the transaction (usually using a UnitOfWork class).
Quick example:
public class Item
{
public int ID { get; set; }
public string Title { get; set; }
public virtual ICollection<Bid> Bids { get; set; }
}
public class User
{
public int ID { get; set; }
public string Username{ get; set; }
public string Email { get; set; }
public string Password { get; set; }
public virtual ICollection<Bid> Bids { get; set; }
}
public class Bid
{
public int ID { get; set; }
public float Amount { get; set; }
public DateTime Date { get; set; }
public virtual Item Item { get; set; }
public virtual User User { get; set; }
}
Then I would simply create instances of the Bid entity.
public void PlaceBid(User user, Item item, int amount)
{
if (ValidateBid(amount, user, item))
{
Bid bid = new Bid
{
Amount = amount,
Date = DateTime.Now,
User = user,
Item = item
};
try
{
repository.Add(bid);
unitOfWork.Commit();
}
catch (Exception ex)
{
//TODO: Log the exception
throw;
}
}
}