I'm using SQLite extension to create a DB. OnetoOne relation and ManytoOne relations work fine, I'm using InsertorReplacewithChildren to manage new and modified elements. But when it comes to OnetoMany relations I have some problems.
Following SQLite-Net Extensions Manual I have added this in my parent class:
[PrimaryKey, AutoIncrement]
public int ID_child { get; set; }
...
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<ClinicalTest> ClinicalTests_DB { get; set; }
and this in my child class:
[PrimaryKey, AutoIncrement]
public int ID_clinicaltest { get; set; }
[ForeignKey(typeof(Child))]
public int ID_child { get; set; }
The problem is that if I change some fields of an element in my ClinicalTest and I call either UpdatewithChildren(FatherClassInstance) or InsertorReplacewithChildren(FatherClassInstance) the result is that in the ClinicalTests Table I have two rows: one is the updated element (with the correct foreingkey) and one is the old element (without any foreingkey).
I would have expected just one row with the updated element.
Am I doing something wrong?
Should I clean manually these useless elements?
Thanks,
Alex
Nothing, sorry for the trouble.
In my code the ID of the clinical test was "lost" during some passages. That was the cause of the problem.
Related
I have a problem trying to correctly configure a relationship in EF. I have used EF code first to generate classes from an existing database. The first table holds a list of instructions, the second holds a record of the state that each instruction is in.
Tables (simplified):
Instruction
-----------
InstructionID
CurrentInstructionStateHistoryID
InstructionStateHistory
-----------------------
InstructionStateHistoryID
InstructionID
State
So you can see that there are two relationships between the tables - a 1-many relationship based on InstructionID, which I'm not interested in, and have therefore deleted the properties for. The second relationship is based on the CurrentInstructionStateHistoryID property, which points to the "current" state of the instruction.
The classes are as follows:
public partial class Instruction
{
[Key]
public int InstructionID { get; set; }
public int? CurrentInstructionStateHistoryID { get; set; }
public virtual CurrentInstructionStateHistory InstructionStateHistory { get; set; }
}
public partial class InstructionStateHistory
{
[Key]
public int InstructionStateHistoryID { get; set; }
public int InstructionID { get; set; }
public string State { get; set; }
public virtual Instruction tblInstruction { get; set; }
}
Here's the fluent API setup to define the relationship:
modelBuilder.Entity<InstructionStateHistory>()
.HasRequired(e => e.tblInstruction)
.WithOptional(e => e.CurrentInstructionStateHistory);
So, it all compiles and runs. But when I get to a bit of code like this:
Instruction instruction = await _dal.InstructionRepository.Find(claimID);
InstructionStateHistory history = i.CurrentInstructionStateHistory;
I can see that the instruction is populated correctly, let's say the Id is 1234. When I examine the InstructionStateHistory object, what I want to see is that it's InstructionID is 1234, but instead what I see is that it's InstructionStateHistoryID, i.e. is's primary key, is 1234 and that it's related to a completely different instruction.
Somehow I need to tell EF that Instruction.CurrentInstructionStateHistoryID links to InstructionStateHistory.InstructionStateHistoryID.
I've tried many combinations of data annotations and fluent setup but have been unable to find a combination that actually works, either I get the above result or a runtime error. Any help gratefully accepted!
It seems like EF just can't handle this case, so the solution was to forget the concept of a "current" InstructionStateHistory. Instead I added a date field to the InstructionStateHistory table, and then changed the Instruction class to have a regular collection property as follows:
public virtual ICollection<InstructionStateHistory> InstructionStateHistories{ get; set; }
Then when I need the "current" state I just query the colection, sort by date and take the latest one.
I have a issue with entity framework 6 not updating the foreign key when I try to update a entity object. It works on insert (but then I have to set the state to Unchanged for not to reinsert a new entity in the foreign key table). I am using code first approach and generated the models myself. It's a web application so the entity objects gets detached, so I have to reattach them.
I've created a simplified example so it's easy to explain what my problem is. In this example I have a car object which has a one to many relation to make. I want to update a car and change what make it is and its name. The name is updated but not the foreign key value. How do I go ahead to get the foreign key to be updated too?
The code handeling the attaching
public void UpdateCars(Car car){
var dbContext = new CarsDbContext(); //Inherits DbContext
dbContext.Cars.Attach(car);
dbContext.Entry(car).State = EntityState.Modified;
dbContext.SaveChanges();
}
The car Entity
[Table("Car")]
public class Car
{
public Guid Id { get; set; }
public String Name { get; set; }
public virtual Make Make { get; set; }
}
[Table("Make")]
public class Make
{
public Guid Id { get; set; }
public String Name { get; set; }
}
Edit:
I did a few more changes with help from comments (thanks guys!) and I made something work but it feels like I'm doing it the wrong way because the code is far from pretty. Here's what I did:
Modified the Car object to:
public String Name { get; set; }
public Guid Make_Id
[ForeignKey("Make_Id")]
public virtual Make Make { get; set; }
In my update
var dbContext = new CarsDbContext(); //Inherits DbContext
car.Make_Id = car.Make.Id;
dbContext.Cars.Attach(car);
There surely must be a better practice around this when doing EF code first when working with detached entities?
I ended up using graphdiff which solved all my problems. Also when my entities became more complex and it tried to attachs same entity several times. Here's a article to read about it: http://blog.brentmckendrick.com/introducing-graphdiff-for-entity-framework-code-first-allowing-automated-updates-of-a-graph-of-detached-entities/
I have a base class with ID as Primary Key and 3 version numbers.
[NotNull]
public virtual int Id { get; private set; }
[NotNull]
[NotUpdatable]
public virtual int BaseVersion { get; set; }
[NotNull]
[NotUpdatable]
public virtual int MajorVersion { get; set; }
[NotNull]
[NotUpdatable]
public virtual int MinorVersion { get; set; }
Now I want to persist the object again if it gets a new version number or if it does not exist in the database.
foreach (var dataObject in unitOfWork.NewObjects)
{
if (dataObject.Id > 0)
{
_transactionHelper.GetSession().SaveOrUpdate(dataObject.DeepClone());
continue;
}
_transactionHelper.GetSession().SaveOrUpdate(dataObject);
}
My idea was to make a deepclone but sadly (for me) Nhibernate only updates the existing datarecord. I got some succes with
_transactionHelper.GetSession().Evict(dataObject);
_transactionHelper.GetSession().Save(dataObject.DeepClone());
But then Nhibernate Cascading features does not working properly and I get some times this exception detached entity passed to persist (what is correct).
Some Ideas? Or do i have to progamm is by myself :/
Thanks!
I solved this problem by writing my own mapping container which tracks the state of a relation. I think the main problem was/is that I used my own composite tables (I needed to add some values like active).
To persist an allready persisted entity I used:
_transactionHelper.GetSession().Evict(dataObject);
dataObject.Id = 0;
_transactionHelper.GetSession().Save(dataObject);
It looks like this solution works very well for my problem.
I've defined two tables in SQL: "Inquerito" and "Pergunta", and a third table "Inquerito_Pergunta" to make the many-to-many relationship. In that last table, the primary key is both the primary key of the Inquerito and the Pergunta.
I'am supposed to add as many as "Perguntas" as I want into an "Inquerito" instance. And, it's important to keep the insertion order, so when I'm showing it to the user it's shown in the same order. A "Pergunta" can also have multiple "Inquerito", but the order doesn't matter in that case.
I'm using MVC 4 Entity Framework and my Models are defined like this:
public partial class Inquerito
{
public Inquerito()
{
this.Pergunta = new List<Pergunta>();
}
public System.Guid id { get; set; }
public virtual ICollection<Pergunta> Pergunta { get; set; }
}
public partial class Pergunta
{
public Pergunta()
{
this.Inquerito = new List<Inquerito>();
}
public System.Guid id { get; set; }
public virtual ICollection<Inquerito> Inquerito { get; set; }
}
As you can see I've already changed the default HashSet to a List.
To save all stuff to the database I do:
inquerito.Pergunta.Add(pergunta);
db.Pergunta.Add(pergunta);
db.Inquerito.Add(inquerito);
The problem is the insertion order is lost.
After adding all "Pergunta" that I want I do:
// Grava alterações e desconecta da base de dados.
db.SaveChanges();
Inquerito inquerito1 = db.Inquerito.Find(inquerito.id);
if (inquerito1 != null)
{
foreach (Pergunta p in inquerito1.Pergunta.ToList())
{
System.Diagnostics.Debug.WriteLine("__pergunta: " + p.descricao);
}
}
db = new quest_geralEntities();
inquerito1 = db.Inquerito.Find(inquerito.id);
if (inquerito1 != null)
{
foreach (Pergunta p in inquerito1.Pergunta.ToList())
{
System.Diagnostics.Debug.WriteLine("__pergunta: " + p.descricao);
}
}
So, the first time I print all the "Pergunta" linked to that "Inquerito" everything is shown in the right order (insertion order), but when I update the context, with: "new quest_geralEntities()" when I print it again the insertion order is completely lost.
I've been struggling with this problem for several hours now and I can't find a solution. I hope I've been clear enough to be helped.
Thanks.
If you want to maintain insertion order, I recommend using a field containing an int that increments. You can add an int identity column without it being the primary key and use that column to sort on, maintaining your insertion order.
You can try to change the property type of your relation :
public virtual IList<Inquerito> Inquerito { get; set; }
public virtual IList<Pergunta> Pergunta { get; set; }
You'll need to regenerate the database schema. I'm not sure if it's working on EF, but in NHibernate, it works.
Hope it helps !
I need to track a change history of some database objects in a MVC .NET application using the code first approach.
Here is what is meant by history table:
http://database-programmer.blogspot.de/2008/07/history-tables.html
I would use a history table for it, if I would write the SQL queries myself. But in the code first approach the SQL is generated... and I would like to stick to this paradigm.
The goal is a structure that holds all "old" revisions of changed/deleted entries together with some additional information (e.g. timestamp, user who changed it, ...)
Any ideas?
Regards,
Stefan
To be more specific - here is some code example:
public class Node {
public int NodeID { get; set; }
public string? data { get; set; } // sample data
}
public class NodeHistory {
public int NodeID { get; set; }
public string? data { get; set; }
public int UserID { get; set; }
public DataTime timestamp { get; set; }
}
What I need is some "framework" assistance to be able to add an entry to NodeHistory whenever a change is -persisted- to table the Node structure.
That means: Just overriding the set-method isn't a solution, as it would also create an entry, if the change to a "Node" is not persisted at the end (e.g. roleback).
I think the best approach for me would be to use a repository pattern and do the insertion into the NodeHistory table on every operation on the Node object that you see fit to keep a history of.
EDIT: Some code
public class NodeRepository{
public Node EditNode(Node toEdit, int userId){
using(new TransactionScope())
{
//Edit Node in NodeContext like you would anyway without repository
NodeContext.NodeHistories.Add(new NodeHistory(){//initialise NodeHistory stuff here)
NodeContext.SaveChagnes();
}
}
}
public class NodeContext:DbContext{
public DbSet<Node> Nodes{get;set;}
public DbSet<NodeHistory> NodeHistories{get;set;}
}
If you are looking for something simpler than this, then I have no idea what it might be.
This is really something you should do with a trigger. Yes, you have to write some sql for it, but then history is updated no matter how the update occurs, either manually, or through some other means.