How can I update all the records with Keyword_Id = 1 to Keyword_Id = 2?
public class KeywordAddressCategory
{
[Key]
[Column("Keyword_Id", Order = 0)]
public int Keyword_Id { get; set; }
[Key]
[Column("Address_Id", Order = 1)]
public int Address_Id { get; set; }
[Key]
[Column("Category_Id", Order = 2)]
public int Category_Id { get; set; }
}
I get an exception saying that I can't update a key of the entity.
Thanks
This is probably because those three properties are all part of the composite primary key, and as Entity Framework elegantly points out: you can't change the primary key value.
If this is at all an option, I would consider NOT using a composite primary key but a separate primary key for this class. You'll find it makes using foreign keys a lot simpler.
So, something like this:
[Key]
public int KeywordAddressCategoryId { get; set; }
public int Keyword_Id { get; set; }
public int Address_Id { get; set; }
public int Category_Id { get; set; }
With this system identity constraints, foreign keys, passing around id values as route values or as hidden fields in forms, ... all become much easier. And for your question: you can then easily change the Keyword_Id value because you CAN change a foreign key value easily.
I know this doesn't really answer your question, because I haven't told you how you can actually change the value, but I wanted to post this answer anyway so maybe you could reconsider your database structure.
Edit: see this question on how you can achieve what you want, if you really can't or aren't willing to change your DB structure: Update part of primary key Entity Framework 4.0
Related
I'm using EF6.2.0.
I need to create a many-many relationship between two POCO classes, but I need to add a custom property against the link.
So, I created this class to serve as my many-many link POCO:
class SampleGroupSpecies
{
[Key, Column(Order = 0)]
public int GroupId { get; set; }
[Key, Column(Order = 1)]
public int SpeciesId { get; set; }
public bool IsContaminated { get; set; }
[Required]
public virtual Group Group { get; set; }
[Required]
public virtual Species Species { get; set; }
}
however, when EF generates the table, I get this:
dbo.SampleGroupSpecies
Columns
GroupId (PK, FK, int, not null)
SpeciesId (PK, int, not null)
IsContaminated (bit, not null)
Species_Id (FK, int, not null)
As you can see, it's creating its own "Species_Id" column and using that as the foreign key, but that's not what I want.
I can obviously add a GroupSpeciesId column, set that as the only [key] and it'll all work as if by magic, but that's not good design.
I'm trying to avoid using fluent and just use annotations if possible.
Someone tell me where I've gone wrong :)
This was caused by me setting the navigation property incorrectly on the Species POCO - It was not set as a collection of SampleGroupSpecies, but as a single - meaning EF was correctly trying to create a one-many relationship, but I was trying to force it to create a many-to-many when it couldn't :)
Solution was to check both related POCOs to make sure their navigation properties are set as a collection, rather than a single instance.
I have a solution which uses Entity Framework to insert invoices to a database table. These invoices reference an order, which in turn also references an order item collection.
In this instance I am trying to add an order to the database, however the code is inside a new DbContext and so I need to attach the order and order items to the context, as these already exist in the database and shouldn't be re-added.
I've cut down the model properties for the sake of demonstration:
public class Invoice {
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int InvoiceId { get; set; }
public string OrderNumber { get; set; }
...
public virtual List<InvoiceLineItem> LineItems { get; set; }
}
public class InvoiceLineItem {
[Key]
public int Id { get; set; }
...
public ShopifyOrderItem { get; set; }
}
public class ShopifyOrder {
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public long Id { get; set; }
public int OrderNumber { get; set; }
...
public OrderInvoiceStatus InvoiceStatus { get; set; }
public virtual List<ShopifyOrderItem> OrderItems { get; set; }
}
public class ShopifyOrderItem {
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public long Id { get; set; }
...
[Required]
public virtual ShopifyOrder ShopifyOrder { get; set; }
}
In the invoice engine, I'm running the following code for each invoice to add it to the database:
ShopifyOrder order = await db.ShopifyOrders.SingleOrDefaultAsync(x => x.OrderNumber.ToString() == inv.OrderNumber);
if (order != null) {
// Attach marketplace entity to the invoice to avoid duplicate primary key exceptions
db.Marketplaces.Attach(inv.Marketplace);
db.Invoices.Add(inv);
order.InvoiceStatus = OrderInvoiceStatus.InProgress;
}
I've tried a number of methods to try and attach the states, however they all throw errors.
inv.LineItems.ForEach(li => {
db.Entry(li).State = EntityState.Unchanged;
db.Entry(li.ShopifyOrderItem).State = EntityState.Unchanged;
db.Entry(li.ShopifyOrderItem.ShopifyOrder).State = EntityState.Modified;
});
The above code returns the following error on save:
EntityFramework: Saving or accepting changes failed because more than one entity of type 'TorroModels.ShopifyOrder' have the same primary key value. Ensure that explicitly set primary key values are unique. Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model.
What is the best way to attach the LineItems/ShopifyOrderItems without trying to attach the ShopifyOrder connected property multiple times?
Sorry to say but it seems that you need to follow the best practice first when constructing a relationship. You may follow this link :
http://www.entityframeworktutorial.net/entity-relationships.aspx
In short :
Avoid using only "Id" in every entity, or you can use attributes to map between the physical name and the property name
It seems that you have circular references here, so maybe you could simplify it first
Next, you can read this link :
http://www.entityframeworktutorial.net/EntityFramework5/attach-disconnected-entity-graph.aspx
if you need to know more about what's the best practice of attaching entities, but in my opinion, just don't abuse this feature, because using normal CRUD should be sufficient most of the time.
I'm sorry I cannot help you more than this, because of lack of information I may need, and with my reputation I still cannot comment directly in your post to ask for it.
It is a known issue that SQLite.Net-PCL does not support composite PKs, a feature I need in my case if I do not want to fall back to constructs like
create table something(value varchar primary key not null);
insert into something(value) values("$Value1,$Value2");
Manually (without using ORM) creating a table with a composite primary key also does not work, throwing the same SQLiteException, telling me that my table has multiple primary keys.
The table's layout is like this
class ChannelBinding {
[PrimaryKey]
public int Id { get; set; }
[PrimaryKey]
public string ChannelId { get; set; }
}
and I was wondering if there is any known workaround that would be able to emulate the behaviour of a composite PK.
You can use a composite unique key.
class ChannelBinding {
[Indexed(Name = "CompositeKey", Order = 1, Unique = true)]
public int Id { get; set; }
[Indexed(Name = "CompositeKey", Order = 2, Unique = true)]
public string ChannelId { get; set; }
}
I am trying to make the AnswerString required to be unique among answers that share the same ModuleID value. How would I go about achieving this?
public class Answer
{
public int AnswerID { get; set; }
[MaxLength(25)]
[Required]
[Key]
public string AnswerString { get; set; }
public int ModuleID { get; set; }
public int PictureCount { get; set; }
}
Add this attribute to AnswerString:
[Index("IX_AnswerStringModuleId",2,IsUnique = true)]
Then add this attribute to ModuleId:
[Index("IX_AnswerStringModuleId",1, IsUnique = true)]
Basically this sets up a unique constraint where the combo of ModuleId and AnswerString must be unique.
See this answer as well: Unique Key constraints for multiple columns in Entity Framework
I would recommend making an attribute for the property which would evaluate at the class or property level. This would apply your business logic within the object/model and not rely on EF. If your intent is not to do as such, then I recommend the attributes suggested above or applying a constraint on the table itself.
I wonder, if there is any way ,
to use Database-first approach with manually generated classes (models) in advance(just like Code-first approach),
but without using auto-generated code which Entity Framework creates using Database-first approach?
I have 3 Classes(first two of them Student and Courses have many to many relationship), which represents models:
First one is Student:
public class Student
{
public int StudentID { get; set;}
public string Name { get; set;}
public DateTime BirthDate { get; set;}
public ICollection<StudentToCourse> StudentToCourses { get; set; }
public Student()
{
StudentToCourses = new List<StudentToCourse>();
}
}
Then Course:
public class Course
{
public int CourseID { get; set; }
public string CourseName { get; set; }
public ICollection<StudentToCourse> StudentToCourses { get; set; }
public Course()
{
StudentToCourses = new List<StudentToCourse>();
}
}
And Relation/Intermediate Class with additional properties StudentToCourse:
public class StudentToCourse
{
[Key, Column(Order = 0)]
public int StudentID { get; set; }
[Key, Column(Order = 1)]
public int CourseID { get; set; }
[Key, Column(Order = 2)]
public DateTime Date { get; set; }
public virtual Student Student { get; set; }
public virtual Course Course { get; set; }
//public ICollection<Student> Students { get; set; }
//public ICollection<Course> Courses { get; set; }
public int Grade { get; set; }
}
Also, i created Database, using LocalDb feature in VS 2013
I have 3 Tables:
Courses:
CREATE TABLE [dbo].[Courses]
(
[CourseID] INT NOT NULL PRIMARY KEY IDENTITY,
[CourseName] NVARCHAR(100) NOT NULL,
)
Students:
CREATE TABLE [dbo].[Students]
(
[StudentID] INT NOT NULL PRIMARY KEY IDENTITY,
[Name] NVARCHAR(50) NOT NULL,
[BirthDate] DATETIME NOT NULL,
)
Relation Table StudentsToCourses:
CREATE TABLE [dbo].[StudentsToCourses]
(
[StudentID] INT REFERENCES Students(StudentID) NOT NULL,
[CourseID] INT REFERENCES Courses(CourseID) NOT NULL,
[Date] DATETIME NOT NULL,
[Grade] INT NOT NULL,
PRIMARY KEY (StudentID, CourseID, Date)
)
Unfortunately, i have no luck with this approach, i do get students' data but i don't receive data from relational table and i can't receive all related grades per student.
I searched for related topics in google and in stackoverflow , but all those topics weren't helpful for me, although the example above i found in this topic.
As I suspected, the problem is not whether or not you can have a database and a class model independently. Of course you can! All these generation tools and migration stuff only serve one goal: making life easier, help you keeping both models in sync. But you can do that job yourself just as well. The end result is always: two models that – at runtime – don't interact with each other whatsoever. (Don't interact? No, not as such. There must be a middleman, an ORM, to connect both worlds.)
The reason why you don't get data is because lazy loading does not occur. Your statement is
var listOfGrades = _context.Students.Where(s => s.Name.StartsWith("J"))
.FirstOrDefault().StudentToCourses;
This requires lazy loading, because the FirstOrDefault() statement executes the first part of the query. It renders a Student of which subsequently the StudentToCourses are accessed. But these don't load because the collection is not virtual. It should be
public virtual ICollection<StudentToCourse> StudentToCourses { get; set; }
This enables EF to override the collection in a dynamic proxy object that is capable of lazy loading.
But of course is is more efficient to get the collection in one statement, for example:
var listOfGrades = _context.Students.Include(s => s.StudentToCourses)
.Where(s => s.Name.StartsWith("J"))
.FirstOrDefault().StudentToCourses;
Yes, you can. You just need a context with no initialization strategy (so it doesn't try to create or migrate your existing database):
public class ExistingDatabaseContext : DbContext
{
public ExistingDatabaseContext()
: base("ExistingDatabaseConnectionStringName")
{
Database.SetInitializer<ExistingDatabaseContext>(null);
}
// DbSets here for your "code-first" classes that represent existing database tables
}
Just bear in mind that this context will not be capable of doing migrations or any other form of initialization, so if you have actual true code-first tables in there as well, you'll need a separate context to manage those.